{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<center>\n",
    "<img src=\"../../../img/ods_stickers.jpg\">\n",
    "## Открытый курс по машинному обучению\n",
    "<center>Автор материала: Титаевская Наталья Анатольевна, @Titaevskaya."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# <center>Пример парсинга сайта с помощью scrapy</center>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "В этом материале кратко расскажу о библиотеке scrapy (https://scrapy.org/). Библиотека имеет очень много возможностей, я разберу только основные, которых, впрочем, будет достаточно для базового парсинга данных. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Для примера будем парсить небольшой объем данных. А поскольку скоро лето, то и данные будут летними - \n",
    "каталог всех зарегистрированных пляжей России."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Эти данные находятся в открытом доступе по адресу http://www.classification-tourism.ru/index.php/displayBeach/index"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Создаем проект"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "После установки scrapy с помощью pip становится доступна утилита командной строки `scrapy`. Вообще взаимодействие со scrapy происходит из командой строки, из ноутбука запускать классы-парсеры неудобно, поэтому будем работать, как работали с vw."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Перед тем, как начинать парсинг, необходимо создать scrapy проект. Это делается командой `scrapy startproject <имя-проекта>`. scrapy создаст каталог <имя-проекта> и в нем расположит заготовки для необходимых файлов. В частности, там будут файл настроек settings.py, директория с обработчиками html-страниц (они в терминах scrapy называются спайдерами), файл дополнительной обработки спаршенных данных pipelines.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Этот ноутбук фактически находится в директории scrapy проекта scrapy_tourism."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "scrapy_tourism/__init__.py   scrapy_tourism/settings.py\r\n",
      "scrapy_tourism/pipelines.py\r\n"
     ]
    }
   ],
   "source": [
    "!ls scrapy_tourism/*.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "scrapy_tourism/spiders/beach_spider_0.py\r\n",
      "scrapy_tourism/spiders/beach_spider_1.py\r\n",
      "scrapy_tourism/spiders/beach_spider_2.py\r\n",
      "scrapy_tourism/spiders/__init__.py\r\n"
     ]
    }
   ],
   "source": [
    "!ls scrapy_tourism/spiders/*.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Первый парсер"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Для начала спарсим названия пляжей с одной страницы http://www.classification-tourism.ru/index.php/displayBeach/index. Создадим файл с название `beach_spider_0.py` в директории `spiders/` и опишем там спайдер. Спайдеру необходимы имя `name`; урл, с которго начинать парсинг `start_urls`; и метод обработки скачанного html документа ```parse(self, response)```. Метод ```parse``` должен возвращать с помощью yield готовые спаршенные объекты-словари, в нашем случае словари из одного элемента с ключом title. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "import scrapy\r\n",
      "\r\n",
      "class TourismBeachSpider0(scrapy.Spider):\r\n",
      "    name = \"beach_0\"\r\n",
      "    start_urls = [\r\n",
      "        'http://www.classification-tourism.ru/index.php/displayBeach/index',\r\n",
      "    ]\r\n",
      "\r\n",
      "    def parse(self, response):\r\n",
      "        for obj in response.css('a.field.object-title'):\r\n",
      "            yield {\r\n",
      "                'title': obj.css('::text').extract_first()\r\n",
      "            }\r\n",
      "\r\n"
     ]
    }
   ],
   "source": [
    "!cat scrapy_tourism/spiders/beach_spider_0.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Парсинг документа происходит с помощью css-селекторов, про них подробней можно почитать, например, в\n",
    "[документации scrapy]('https://doc.scrapy.org/en/latest/topics/selectors.html'),\n",
    "по сути это способ обращаться к объектам в html-документе через их названия и классы."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "В данном случае мы находим все объекты тэга `<a>` с классом `field object-title` и достаем из них текстовое содержимое.\n",
    "Чтобы понять, из каких объектов доставать необходимые данные, нужно посмотреть исходный код страницы."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Для запуска парсинга нужно использовать утилиту scrapy:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# !scrapy crawl beach_0 --loglevel ERROR  -o result_0.csv --output-format csv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Здесь `beach_0` - это имя запускаемого спайдера (`TourismBeachSpider0.name`), `-o result_0.csv` - имя выходного файла, `--output-format csv` - формат выходного файла, `--loglevel ERROR` - уровень логирования (здесь повыше, чтобы не спамить логами)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(10, 1)\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style>\n",
       "    .dataframe thead tr:only-child th {\n",
       "        text-align: right;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: left;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>title</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Пляж базы отдыха \"Искра\" ПАО \"Межрегиональная ...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Пляж ФГБУ \"Дом отдыха \"Туапсе\" Управления дела...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Пляж детского оздоровительного лагеря «Альбатр...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Лечебный пляж закрытого акционерного общества ...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Пляж «Бархатные сезоны» непубличного акционерн...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>Пляж Открытого акционерного общества «Санатори...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>Пляж пансионата «Бургас» АО «Пансионат «Бургас»</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>Пляж «Ривьера Санрайз» (Riviera Sunrise Resort...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>пляж \"Оздоровительного комплекса \"Орбита\" АО \"...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>Пляж общества с ограниченной ответственностью ...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                               title\n",
       "0  Пляж базы отдыха \"Искра\" ПАО \"Межрегиональная ...\n",
       "1  Пляж ФГБУ \"Дом отдыха \"Туапсе\" Управления дела...\n",
       "2  Пляж детского оздоровительного лагеря «Альбатр...\n",
       "3  Лечебный пляж закрытого акционерного общества ...\n",
       "4  Пляж «Бархатные сезоны» непубличного акционерн...\n",
       "5  Пляж Открытого акционерного общества «Санатори...\n",
       "6    Пляж пансионата «Бургас» АО «Пансионат «Бургас»\n",
       "7  Пляж «Ривьера Санрайз» (Riviera Sunrise Resort...\n",
       "8  пляж \"Оздоровительного комплекса \"Орбита\" АО \"...\n",
       "9  Пляж общества с ограниченной ответственностью ..."
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "result_beach_0 = pd.read_csv('result_0_ref.csv')\n",
    "\n",
    "print(result_beach_0.shape)\n",
    "result_beach_0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Обработка следующих страниц "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Теперь скачаем название не только с первой страницы списка, а со всех. \n",
    "Для этого нам потребуется переходить на новые страницы и парсить их тем же методом ```parse```.\n",
    "Если в ```parse``` вернуть не `dict`, а объект `scrapy.Request`, то именно это и произойдет - указанный урл скачается и отправится на обработку."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "import scrapy\r\n",
      "\r\n",
      "class TourismBeachSpider1(scrapy.Spider):\r\n",
      "    name = \"beach_1\"\r\n",
      "    start_urls = [\r\n",
      "        'http://www.classification-tourism.ru/index.php/displayBeach/index',\r\n",
      "    ]\r\n",
      "\r\n",
      "    def parse(self, response):\r\n",
      "        for obj in response.css('a.field.object-title'):\r\n",
      "            yield {\r\n",
      "                'title': obj.css('::text').extract_first()\r\n",
      "            }\r\n",
      "\r\n",
      "        next_page_href = response.css('li.next a::attr(\"href\")').extract_first()\r\n",
      "        if next_page_href is not None:\r\n",
      "            next_page_url = response.urljoin(next_page_href)\r\n",
      "            yield scrapy.Request(next_page_url, self.parse)\r\n",
      "\r\n"
     ]
    }
   ],
   "source": [
    "!cat scrapy_tourism/spiders/beach_spider_1.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Здесь урлы следующих страниц достаются из объекта атрибута href объекта li.next.\n",
    "Второй аргумент конструктора `scrapy.Request` - это метод, которым будет парситься скачанный документ,\n",
    "в нашем случае тот же `parse`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "# !scrapy crawl beach_1 --loglevel ERROR  -o result_1.csv --output-format csv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(77, 1)\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style>\n",
       "    .dataframe thead tr:only-child th {\n",
       "        text-align: right;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: left;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>title</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Пляж базы отдыха \"Искра\" ПАО \"Межрегиональная ...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Пляж ФГБУ \"Дом отдыха \"Туапсе\" Управления дела...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Пляж детского оздоровительного лагеря «Альбатр...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Лечебный пляж закрытого акционерного общества ...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Пляж «Бархатные сезоны» непубличного акционерн...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                               title\n",
       "0  Пляж базы отдыха \"Искра\" ПАО \"Межрегиональная ...\n",
       "1  Пляж ФГБУ \"Дом отдыха \"Туапсе\" Управления дела...\n",
       "2  Пляж детского оздоровительного лагеря «Альбатр...\n",
       "3  Лечебный пляж закрытого акционерного общества ...\n",
       "4  Пляж «Бархатные сезоны» непубличного акционерн..."
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result_beach_1 = pd.read_csv('result_1_ref.csv')\n",
    "\n",
    "print(result_beach_1.shape)\n",
    "result_beach_1.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Обработка дополнительных объектов"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Мы парсили только названия пляжей, теперь давайте спарсим дополнительную информацию: например, адрес и категорию.\n",
    "Для этого будем переходить на страницу пляжа ([например](http://www.classification-tourism.ru/index.php/displayBeach/102)) и доставать оттуда необходимые данные. Конкретно, эти данные можно было бы спарсить и со страницы-списка, но для целей тьюториала представим, что их там нет."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "import scrapy\r\n",
      "\r\n",
      "class TourismBeachSpider2(scrapy.Spider):\r\n",
      "    name = \"beach_2\"\r\n",
      "    start_urls = [\r\n",
      "        'http://www.classification-tourism.ru/index.php/displayBeach/index',\r\n",
      "    ]\r\n",
      "\r\n",
      "    def parse_item(self, response):\r\n",
      "        fields = {}\r\n",
      "        for obj in response.css('div.detail-field'):\r\n",
      "            field_name = obj.css('span.detail-label::text').extract_first()\r\n",
      "            field_value = obj.css('span.detail-value::text').extract_first()\r\n",
      "            fields[field_name] = field_value\r\n",
      "\r\n",
      "        yield {\r\n",
      "            'reg_id': fields['Регистрационный номер в Федеральном перечне:'],\r\n",
      "            'full_name': fields['Полное наименование классифицированного объекта:'],\r\n",
      "            'name': fields['Cокращенное наименование классифицированного объекта:'],\r\n",
      "            'category': fields['Присвоенная категория:'],\r\n",
      "            'address': fields['Адрес:'],\r\n",
      "        }\r\n",
      "\r\n",
      "\r\n",
      "    def parse(self, response):\r\n",
      "        for obj in response.css('a.field.object-title'):\r\n",
      "            item_href = obj.css('::attr(\"href\")').extract_first()\r\n",
      "            yield scrapy.Request(response.urljoin(item_href), self.parse_item)\r\n",
      "\r\n",
      "        next_page_href = response.css('li.next a::attr(\"href\")').extract_first()\r\n",
      "        if next_page_href is not None:\r\n",
      "            next_page_url = response.urljoin(next_page_href)\r\n",
      "            yield scrapy.Request(next_page_url, self.parse)\r\n",
      "\r\n"
     ]
    }
   ],
   "source": [
    "!cat scrapy_tourism/spiders/beach_spider_2.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Здесь мы достаем ссылки на страницы пляжей через атрибут `href` объектов `a.field.object-title`, а сами страницы парсим\n",
    "с помощью уже другого метода `parse_item`, который передается как колбэк в `scrapy.Request`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "# !scrapy crawl beach_2 --loglevel ERROR  -o result_2.csv --output-format csv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(77, 5)\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style>\n",
       "    .dataframe thead tr:only-child th {\n",
       "        text-align: right;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: left;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>reg_id</th>\n",
       "      <th>full_name</th>\n",
       "      <th>name</th>\n",
       "      <th>category</th>\n",
       "      <th>address</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>330000087</td>\n",
       "      <td>Пляж общества с ограниченной ответственностью ...</td>\n",
       "      <td>Пляж ООО Санаторий «Мечта»</td>\n",
       "      <td>желтый флаг (3 категория)</td>\n",
       "      <td>353456, Краснодарский край, г. Анапа, Пионерск...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>330000089</td>\n",
       "      <td>пляж \"Оздоровительного комплекса \"Орбита\" АО \"...</td>\n",
       "      <td>пляж \"Оздоровительного комплекса \"Орбита\"</td>\n",
       "      <td>зеленый флаг (2 категория)</td>\n",
       "      <td>352840,Туапсинский район, с.Ольгинка, оздорови...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>330000091</td>\n",
       "      <td>Пляж «Ривьера Санрайз» (Riviera Sunrise Resort...</td>\n",
       "      <td>Пляж «Ривьера Санрайз» (Riviera Sunrise Resort...</td>\n",
       "      <td>синий флаг (1 категория)</td>\n",
       "      <td>298500, Республика Крым, г. Алушта, ул. Ленина, 2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>330000095</td>\n",
       "      <td>Пляж пансионата «Бургас» АО «Пансионат «Бургас»</td>\n",
       "      <td>Пляж пансионата «Бургас»</td>\n",
       "      <td>зеленый флаг (2 категория)</td>\n",
       "      <td>354364, Краснодарский край, г. Сочи, ул. Ленин...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>330000096</td>\n",
       "      <td>Пляж Открытого акционерного общества «Санатори...</td>\n",
       "      <td>Пляж ОАО «Санаторий «Южное взморье»</td>\n",
       "      <td>синий флаг (1 категория)</td>\n",
       "      <td>354340, Краснодарский край, г. Сочи, ул. Калин...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      reg_id                                          full_name  \\\n",
       "0  330000087  Пляж общества с ограниченной ответственностью ...   \n",
       "1  330000089  пляж \"Оздоровительного комплекса \"Орбита\" АО \"...   \n",
       "2  330000091  Пляж «Ривьера Санрайз» (Riviera Sunrise Resort...   \n",
       "3  330000095    Пляж пансионата «Бургас» АО «Пансионат «Бургас»   \n",
       "4  330000096  Пляж Открытого акционерного общества «Санатори...   \n",
       "\n",
       "                                                name  \\\n",
       "0                         Пляж ООО Санаторий «Мечта»   \n",
       "1          пляж \"Оздоровительного комплекса \"Орбита\"   \n",
       "2  Пляж «Ривьера Санрайз» (Riviera Sunrise Resort...   \n",
       "3                          Пляж пансионата «Бургас»    \n",
       "4                Пляж ОАО «Санаторий «Южное взморье»   \n",
       "\n",
       "                     category  \\\n",
       "0   желтый флаг (3 категория)   \n",
       "1  зеленый флаг (2 категория)   \n",
       "2    синий флаг (1 категория)   \n",
       "3  зеленый флаг (2 категория)   \n",
       "4    синий флаг (1 категория)   \n",
       "\n",
       "                                             address  \n",
       "0  353456, Краснодарский край, г. Анапа, Пионерск...  \n",
       "1  352840,Туапсинский район, с.Ольгинка, оздорови...  \n",
       "2  298500, Республика Крым, г. Алушта, ул. Ленина, 2  \n",
       "3  354364, Краснодарский край, г. Сочи, ул. Ленин...  \n",
       "4  354340, Краснодарский край, г. Сочи, ул. Калин...  "
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result_beach_2 = pd.read_csv('result_2_ref.csv')\n",
    "\n",
    "print(result_beach_2.shape)\n",
    "result_beach_2.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Геокодирование объектов"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Мы спарсили каталог пляжей с адресами. Допустим, мы хотим адреса геокодировать, то есть преобразовывать их в координаты.\n",
    "Для этого хорошо подойдет механизм пайплайнов из scrapy - каждый спаршенный объект дополнительно\n",
    "обрабатывается произвольным классом, в нашем случае геокодировщиком."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "import urllib.request\r\n",
      "import requests\r\n",
      "\r\n",
      "class GeocoderPipeline(object):\r\n",
      "    def process_item(self, item, spider):\r\n",
      "        address = item['address']\r\n",
      "        print(address)\r\n",
      "        geocode_url = 'https://geocode-maps.yandex.ru/1.x/?format=json&geocode={0}'.format(\r\n",
      "            urllib.request.quote(address))\r\n",
      "        response = requests.get(geocode_url)\r\n",
      "\r\n",
      "        lat, lon = None, None\r\n",
      "        if response.status_code == 200:\r\n",
      "            data = response.json()\r\n",
      "            geocoder_objects = data['response']['GeoObjectCollection']['featureMember']\r\n",
      "            if geocoder_objects:\r\n",
      "                coordinates = geocoder_objects[0]['GeoObject']['Point']['pos'].split()\r\n",
      "                lat, lon = float(coordinates[1]), float(coordinates[0])\r\n",
      "\r\n",
      "        item['lat'] = lat\r\n",
      "        item['lon'] = lon\r\n",
      "\r\n",
      "        return item\r\n",
      "\r\n"
     ]
    }
   ],
   "source": [
    "!cat scrapy_tourism/pipelines.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Здесь мы помощью [геокодировщика Яндекса](https://tech.yandex.ru/maps/geocoder/) получаем из адреса координаты\n",
    "и сохраняем их в спаршенный объект"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Для того, чтобы пайплайн заработал, его необходимо добавить в `settings.py`:<br>\n",
    "\n",
    "```ITEM_PIPELINES = {\n",
    "  'scrapy_tourism.pipelines.GeocoderPipeline': 300,\n",
    "}```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [],
   "source": [
    "# !scrapy crawl beach_2 --loglevel ERROR  -o result_3.csv --output-format csv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(77, 7)\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style>\n",
       "    .dataframe thead tr:only-child th {\n",
       "        text-align: right;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: left;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>reg_id</th>\n",
       "      <th>full_name</th>\n",
       "      <th>name</th>\n",
       "      <th>category</th>\n",
       "      <th>address</th>\n",
       "      <th>lat</th>\n",
       "      <th>lon</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>330000087</td>\n",
       "      <td>Пляж общества с ограниченной ответственностью ...</td>\n",
       "      <td>Пляж ООО Санаторий «Мечта»</td>\n",
       "      <td>желтый флаг (3 категория)</td>\n",
       "      <td>353456, Краснодарский край, г. Анапа, Пионерск...</td>\n",
       "      <td>44.934010</td>\n",
       "      <td>37.312253</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>330000089</td>\n",
       "      <td>пляж \"Оздоровительного комплекса \"Орбита\" АО \"...</td>\n",
       "      <td>пляж \"Оздоровительного комплекса \"Орбита\"</td>\n",
       "      <td>зеленый флаг (2 категория)</td>\n",
       "      <td>352840,Туапсинский район, с.Ольгинка, оздорови...</td>\n",
       "      <td>44.201336</td>\n",
       "      <td>38.889165</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>330000091</td>\n",
       "      <td>Пляж «Ривьера Санрайз» (Riviera Sunrise Resort...</td>\n",
       "      <td>Пляж «Ривьера Санрайз» (Riviera Sunrise Resort...</td>\n",
       "      <td>синий флаг (1 категория)</td>\n",
       "      <td>298500, Республика Крым, г. Алушта, ул. Ленина, 2</td>\n",
       "      <td>44.668763</td>\n",
       "      <td>34.412258</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>330000095</td>\n",
       "      <td>Пляж пансионата «Бургас» АО «Пансионат «Бургас»</td>\n",
       "      <td>Пляж пансионата «Бургас»</td>\n",
       "      <td>зеленый флаг (2 категория)</td>\n",
       "      <td>354364, Краснодарский край, г. Сочи, ул. Ленин...</td>\n",
       "      <td>43.489340</td>\n",
       "      <td>39.888028</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>330000096</td>\n",
       "      <td>Пляж Открытого акционерного общества «Санатори...</td>\n",
       "      <td>Пляж ОАО «Санаторий «Южное взморье»</td>\n",
       "      <td>синий флаг (1 категория)</td>\n",
       "      <td>354340, Краснодарский край, г. Сочи, ул. Калин...</td>\n",
       "      <td>43.430094</td>\n",
       "      <td>39.914600</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      reg_id                                          full_name  \\\n",
       "0  330000087  Пляж общества с ограниченной ответственностью ...   \n",
       "1  330000089  пляж \"Оздоровительного комплекса \"Орбита\" АО \"...   \n",
       "2  330000091  Пляж «Ривьера Санрайз» (Riviera Sunrise Resort...   \n",
       "3  330000095    Пляж пансионата «Бургас» АО «Пансионат «Бургас»   \n",
       "4  330000096  Пляж Открытого акционерного общества «Санатори...   \n",
       "\n",
       "                                                name  \\\n",
       "0                         Пляж ООО Санаторий «Мечта»   \n",
       "1          пляж \"Оздоровительного комплекса \"Орбита\"   \n",
       "2  Пляж «Ривьера Санрайз» (Riviera Sunrise Resort...   \n",
       "3                          Пляж пансионата «Бургас»    \n",
       "4                Пляж ОАО «Санаторий «Южное взморье»   \n",
       "\n",
       "                     category  \\\n",
       "0   желтый флаг (3 категория)   \n",
       "1  зеленый флаг (2 категория)   \n",
       "2    синий флаг (1 категория)   \n",
       "3  зеленый флаг (2 категория)   \n",
       "4    синий флаг (1 категория)   \n",
       "\n",
       "                                             address        lat        lon  \n",
       "0  353456, Краснодарский край, г. Анапа, Пионерск...  44.934010  37.312253  \n",
       "1  352840,Туапсинский район, с.Ольгинка, оздорови...  44.201336  38.889165  \n",
       "2  298500, Республика Крым, г. Алушта, ул. Ленина, 2  44.668763  34.412258  \n",
       "3  354364, Краснодарский край, г. Сочи, ул. Ленин...  43.489340  39.888028  \n",
       "4  354340, Краснодарский край, г. Сочи, ул. Калин...  43.430094  39.914600  "
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result_beach_3 = pd.read_csv('result_3_ref.csv')\n",
    "\n",
    "print(result_beach_3.shape)\n",
    "result_beach_3.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Визуализация"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Отобразим полученные данные на карте. Для этого нам потребуется библиотека folium.\n",
    "Сделаем красиво: будем ставить маркеры цвета, соответствующего категории пляжа."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "синий флаг (1 категория)      37\n",
       "желтый флаг (3 категория)     25\n",
       "зеленый флаг (2 категория)    15\n",
       "Name: category, dtype: int64"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "beach_df = result_beach_3.copy()\n",
    "\n",
    "beach_df.category.value_counts()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [],
   "source": [
    "COLOR_DICT = {\n",
    "    'синий флаг (1 категория)': 'blue',\n",
    "    'зеленый флаг (2 категория)': 'green',\n",
    "    'желтый флаг (3 категория)': 'beige',\n",
    "}\n",
    "\n",
    "beach_df['color'] = beach_df['category'].apply(lambda c: COLOR_DICT[c])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [],
   "source": [
    "import folium\n",
    "\n",
    "SOCHI = [43.585525, 39.723062]\n",
    "m = folium.Map(location=SOCHI, tiles='Stamen Terrain', zoom_start=11)\n",
    "\n",
    "for i in range(len(beach_df)):\n",
    "    folium.Marker(beach_df.loc[i, ['lat', 'lon']].values,\n",
    "                  popup=beach_df.loc[i, 'name'],\n",
    "                  icon=folium.Icon(color=beach_df.loc[i, 'color'], icon='')) \\\n",
    "        .add_to(m)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div style=\"width:100%;\"><div style=\"position:relative;width:100%;height:0;padding-bottom:60%;\"><iframe src=\"data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+CjxoZWFkPiAgICAKICAgIDxtZXRhIGh0dHAtZXF1aXY9ImNvbnRlbnQtdHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04IiAvPgogICAgPHNjcmlwdD5MX1BSRUZFUl9DQU5WQVMgPSBmYWxzZTsgTF9OT19UT1VDSCA9IGZhbHNlOyBMX0RJU0FCTEVfM0QgPSBmYWxzZTs8L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS4yLjAvZGlzdC9sZWFmbGV0LmpzIj48L3NjcmlwdD4KICAgIDxzY3JpcHQgc3JjPSJodHRwczovL2FqYXguZ29vZ2xlYXBpcy5jb20vYWpheC9saWJzL2pxdWVyeS8xLjExLjEvanF1ZXJ5Lm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvanMvYm9vdHN0cmFwLm1pbi5qcyI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0IHNyYz0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvTGVhZmxldC5hd2Vzb21lLW1hcmtlcnMvMi4wLjIvbGVhZmxldC5hd2Vzb21lLW1hcmtlcnMuanMiPjwvc2NyaXB0PgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2xlYWZsZXRAMS4yLjAvZGlzdC9sZWFmbGV0LmNzcyIgLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9ib290c3RyYXAvMy4yLjAvY3NzL2Jvb3RzdHJhcC5taW4uY3NzIiAvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL21heGNkbi5ib290c3RyYXBjZG4uY29tL2Jvb3RzdHJhcC8zLjIuMC9jc3MvYm9vdHN0cmFwLXRoZW1lLm1pbi5jc3MiIC8+CiAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9Imh0dHBzOi8vbWF4Y2RuLmJvb3RzdHJhcGNkbi5jb20vZm9udC1hd2Vzb21lLzQuNi4zL2Nzcy9mb250LWF3ZXNvbWUubWluLmNzcyIgLz4KICAgIDxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvTGVhZmxldC5hd2Vzb21lLW1hcmtlcnMvMi4wLjIvbGVhZmxldC5hd2Vzb21lLW1hcmtlcnMuY3NzIiAvPgogICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJodHRwczovL3Jhd2dpdC5jb20vcHl0aG9uLXZpc3VhbGl6YXRpb24vZm9saXVtL21hc3Rlci9mb2xpdW0vdGVtcGxhdGVzL2xlYWZsZXQuYXdlc29tZS5yb3RhdGUuY3NzIiAvPgogICAgPHN0eWxlPmh0bWwsIGJvZHkge3dpZHRoOiAxMDAlO2hlaWdodDogMTAwJTttYXJnaW46IDA7cGFkZGluZzogMDt9PC9zdHlsZT4KICAgIDxzdHlsZT4jbWFwIHtwb3NpdGlvbjphYnNvbHV0ZTt0b3A6MDtib3R0b206MDtyaWdodDowO2xlZnQ6MDt9PC9zdHlsZT4KICAgIAogICAgICAgICAgICA8c3R5bGU+ICNtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IgewogICAgICAgICAgICAgICAgcG9zaXRpb24gOiByZWxhdGl2ZTsKICAgICAgICAgICAgICAgIHdpZHRoIDogMTAwLjAlOwogICAgICAgICAgICAgICAgaGVpZ2h0OiAxMDAuMCU7CiAgICAgICAgICAgICAgICBsZWZ0OiAwLjAlOwogICAgICAgICAgICAgICAgdG9wOiAwLjAlOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICA8L3N0eWxlPgogICAgICAgIAo8L2hlYWQ+Cjxib2R5PiAgICAKICAgIAogICAgICAgICAgICA8ZGl2IGNsYXNzPSJmb2xpdW0tbWFwIiBpZD0ibWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiIiA+PC9kaXY+CiAgICAgICAgCjwvYm9keT4KPHNjcmlwdD4gICAgCiAgICAKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGJvdW5kcyA9IG51bGw7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgdmFyIG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYiA9IEwubWFwKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ21hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7Y2VudGVyOiBbNDMuNTg1NTI1LDM5LjcyMzA2Ml0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB6b29tOiAxMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heEJvdW5kczogYm91bmRzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5ZXJzOiBbXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmxkQ29weUp1bXA6IGZhbHNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3JzOiBMLkNSUy5FUFNHMzg1NwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHRpbGVfbGF5ZXJfNTMxNzk4NGVjNWY2NGIxNjljZThkMTE3YTYzZTNhYzcgPSBMLnRpbGVMYXllcigKICAgICAgICAgICAgICAgICdodHRwczovL3N0YW1lbi10aWxlcy17c30uYS5zc2wuZmFzdGx5Lm5ldC90ZXJyYWluL3t6fS97eH0ve3l9LmpwZycsCiAgICAgICAgICAgICAgICB7CiAgImF0dHJpYnV0aW9uIjogbnVsbCwKICAiZGV0ZWN0UmV0aW5hIjogZmFsc2UsCiAgIm1heFpvb20iOiAxOCwKICAibWluWm9vbSI6IDEsCiAgIm5vV3JhcCI6IGZhbHNlLAogICJzdWJkb21haW5zIjogImFiYyIKfQogICAgICAgICAgICAgICAgKS5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2Q0YTYyN2ZiMTE1ZTQyNjRiMzkyYWZhZmNkZmE2ODljID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuOTM0MDEsMzcuMzEyMjUzXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uXzhkNzBjYzhlOGNkZjQwNjc5NmIyNTIyYTljODU2OWMyID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdiZWlnZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl9kNGE2MjdmYjExNWU0MjY0YjM5MmFmYWZjZGZhNjg5Yy5zZXRJY29uKGljb25fOGQ3MGNjOGU4Y2RmNDA2Nzk2YjI1MjJhOWM4NTY5YzIpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZmRiMDAxOGVjZjJiNDNkOTlmYTQzMWQxOGMzODU1NWUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMjM2MWYwMzlkYjg5NGVlZjg4MzUwNDQ0YWRlNzgyYWQgPSAkKCc8ZGl2IGlkPSJodG1sXzIzNjFmMDM5ZGI4OTRlZWY4ODM1MDQ0NGFkZTc4MmFkIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDQntCe0J4g0KHQsNC90LDRgtC+0YDQuNC5IMKr0JzQtdGH0YLQsMK7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9mZGIwMDE4ZWNmMmI0M2Q5OWZhNDMxZDE4YzM4NTU1ZS5zZXRDb250ZW50KGh0bWxfMjM2MWYwMzlkYjg5NGVlZjg4MzUwNDQ0YWRlNzgyYWQpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9kNGE2MjdmYjExNWU0MjY0YjM5MmFmYWZjZGZhNjg5Yy5iaW5kUG9wdXAocG9wdXBfZmRiMDAxOGVjZjJiNDNkOTlmYTQzMWQxOGMzODU1NWUpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfYjQ2NzIwYTgwMDBjNDI3OGJmYTEzYzQxYjk4NzE1MjkgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC4yMDEzMzYsMzguODg5MTY1XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uXzJlZGYxYTkzMWZiNzQzNDNiMTQ1YWY1NWUxZjVhNTg3ID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdncmVlbicsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl9iNDY3MjBhODAwMGM0Mjc4YmZhMTNjNDFiOTg3MTUyOS5zZXRJY29uKGljb25fMmVkZjFhOTMxZmI3NDM0M2IxNDVhZjU1ZTFmNWE1ODcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZjY1M2Q2MTNkMDVlNGM5ZDljY2YwMTMwMTg0ZTRhNzUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMzQyZTU0M2NmM2ZkNDI2M2FmZGMwYjhhMmNiNmYzNDggPSAkKCc8ZGl2IGlkPSJodG1sXzM0MmU1NDNjZjNmZDQyNjNhZmRjMGI4YTJjYjZmMzQ4IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qv9C70Y/QtiAi0J7Qt9C00L7RgNC+0LLQuNGC0LXQu9GM0L3QvtCz0L4g0LrQvtC80L/Qu9C10LrRgdCwICLQntGA0LHQuNGC0LAiPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9mNjUzZDYxM2QwNWU0YzlkOWNjZjAxMzAxODRlNGE3NS5zZXRDb250ZW50KGh0bWxfMzQyZTU0M2NmM2ZkNDI2M2FmZGMwYjhhMmNiNmYzNDgpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9iNDY3MjBhODAwMGM0Mjc4YmZhMTNjNDFiOTg3MTUyOS5iaW5kUG9wdXAocG9wdXBfZjY1M2Q2MTNkMDVlNGM5ZDljY2YwMTMwMTg0ZTRhNzUpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfMjc5YWYxZjRjMWM5NDJmOGI5ZmFmNzg3NmMxYzY1NTMgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC42Njg3NjMsMzQuNDEyMjU4XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uXzFhZWZkYTg1Zjg2ODQxZDY4YTkyNGU3Nzg0YTc5MDc4ID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdibHVlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzI3OWFmMWY0YzFjOTQyZjhiOWZhZjc4NzZjMWM2NTUzLnNldEljb24oaWNvbl8xYWVmZGE4NWY4Njg0MWQ2OGE5MjRlNzc4NGE3OTA3OCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9hZmI2MTI1MjQ3MDk0NDUzOGNiZDM2N2E4MmI4YzM0NCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8xN2FkYjM1NzRjZmI0YWRjODQyOWU2ZTdjZGNkZDkyMSA9ICQoJzxkaXYgaWQ9Imh0bWxfMTdhZGIzNTc0Y2ZiNGFkYzg0MjllNmU3Y2RjZGQ5MjEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2IMKr0KDQuNCy0YzQtdGA0LAg0KHQsNC90YDQsNC50LfCuyAoUml2aWVyYSBTdW5yaXNlIFJlc29ydCAmIFNQQSkg0JPQvtGB0YLQuNC90LjRh9C90L7Qs9C+INC60L7QvNC/0LvQtdC60YHQsCDCq9Ca0YDRi9C80YHQutCw0Y8g0KDQuNCy0YzQtdGA0LDCuyDQpNC40LvQuNCw0Lsg0J7QntCeIMKr0JrRgNC+0L3QvtGBPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9hZmI2MTI1MjQ3MDk0NDUzOGNiZDM2N2E4MmI4YzM0NC5zZXRDb250ZW50KGh0bWxfMTdhZGIzNTc0Y2ZiNGFkYzg0MjllNmU3Y2RjZGQ5MjEpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl8yNzlhZjFmNGMxYzk0MmY4YjlmYWY3ODc2YzFjNjU1My5iaW5kUG9wdXAocG9wdXBfYWZiNjEyNTI0NzA5NDQ1MzhjYmQzNjdhODJiOGMzNDQpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfMmM5YWZjNTczZjkwNDJkMDljMDliNzY5NzA2YzE0YjEgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0My40ODkzNCwzOS44ODgwMjhdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fMWI0ZjI2NmUyYTFkNDlmMmJlYjY0NDU5MGM5NDk4ZjQgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2dyZWVuJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzJjOWFmYzU3M2Y5MDQyZDA5YzA5Yjc2OTcwNmMxNGIxLnNldEljb24oaWNvbl8xYjRmMjY2ZTJhMWQ0OWYyYmViNjQ0NTkwYzk0OThmNCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9iYjM3ZGNlYmU4ZjA0MWNmOThjNzQ2NGI1MzE1NWQ3MSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9jZDQwZDA2NWVhY2Q0ZGVkODkwNjkzMjhkMjQ1ZDlhMiA9ICQoJzxkaXYgaWQ9Imh0bWxfY2Q0MGQwNjVlYWNkNGRlZDg5MDY5MzI4ZDI0NWQ5YTIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2INC/0LDQvdGB0LjQvtC90LDRgtCwIMKr0JHRg9GA0LPQsNGBwrsgPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9iYjM3ZGNlYmU4ZjA0MWNmOThjNzQ2NGI1MzE1NWQ3MS5zZXRDb250ZW50KGh0bWxfY2Q0MGQwNjVlYWNkNGRlZDg5MDY5MzI4ZDI0NWQ5YTIpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl8yYzlhZmM1NzNmOTA0MmQwOWMwOWI3Njk3MDZjMTRiMS5iaW5kUG9wdXAocG9wdXBfYmIzN2RjZWJlOGYwNDFjZjk4Yzc0NjRiNTMxNTVkNzEpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfMjBkNTViOGRiNTIzNDYxMDgwNDQ3NGQ3NDNhMWVlZTYgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0My40MzAwOTQsMzkuOTE0Nl0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl8zZDY2MWE1NmUzZDk0ODIzOWJmNTdlYWYwNzY1MTU0OCA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl8yMGQ1NWI4ZGI1MjM0NjEwODA0NDc0ZDc0M2ExZWVlNi5zZXRJY29uKGljb25fM2Q2NjFhNTZlM2Q5NDgyMzliZjU3ZWFmMDc2NTE1NDgpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMTA1ZGNkNGQ0ZWZmNGQ5OWIyZGFkMTk1NzFiYmM4YWUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfNDZmZTU5OGFkZjkxNDhlMzgxYTIxYjNlNDY0OWZkZmQgPSAkKCc8ZGl2IGlkPSJodG1sXzQ2ZmU1OThhZGY5MTQ4ZTM4MWEyMWIzZTQ2NDlmZGZkIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDQntCQ0J4gwqvQodCw0L3QsNGC0L7RgNC40LkgwqvQrtC20L3QvtC1INCy0LfQvNC+0YDRjNC1wrs8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzEwNWRjZDRkNGVmZjRkOTliMmRhZDE5NTcxYmJjOGFlLnNldENvbnRlbnQoaHRtbF80NmZlNTk4YWRmOTE0OGUzODFhMjFiM2U0NjQ5ZmRmZCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzIwZDU1YjhkYjUyMzQ2MTA4MDQ0NzRkNzQzYTFlZWU2LmJpbmRQb3B1cChwb3B1cF8xMDVkY2Q0ZDRlZmY0ZDk5YjJkYWQxOTU3MWJiYzhhZSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9mMDY2N2ZlZjdlMzY0Y2EzYmU3YTAwNWM4NmNiZWM2NCA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjU3NTg4NiwzOS44MDQ0MTNdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fMDIwNWRkYzQxOWJiNDVhMWFlMmRjNzdjMDg1MjVmMmIgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JsdWUnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfZjA2NjdmZWY3ZTM2NGNhM2JlN2EwMDVjODZjYmVjNjQuc2V0SWNvbihpY29uXzAyMDVkZGM0MTliYjQ1YTFhZTJkYzc3YzA4NTI1ZjJiKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzZiZGE4YzkyMTA4MzQwM2JhNThlZDk1NDJlYWUyNmUyID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzMzZWFkNzJhYmMwZjQ1ZDE4MjQ0YWIwZmUwOThjODEyID0gJCgnPGRpdiBpZD0iaHRtbF8zM2VhZDcyYWJjMGY0NWQxODI0NGFiMGZlMDk4YzgxMiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYgwqvQsdCw0YDRhdCw0YLQvdGL0LUg0YHQtdC30L7QvdGLwrsg0J3QkNCeIMKr0KbQtdC90YLRgCDCq9Ce0LzQtdCz0LDCuzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNmJkYThjOTIxMDgzNDAzYmE1OGVkOTU0MmVhZTI2ZTIuc2V0Q29udGVudChodG1sXzMzZWFkNzJhYmMwZjQ1ZDE4MjQ0YWIwZmUwOThjODEyKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfZjA2NjdmZWY3ZTM2NGNhM2JlN2EwMDVjODZjYmVjNjQuYmluZFBvcHVwKHBvcHVwXzZiZGE4YzkyMTA4MzQwM2JhNThlZDk1NDJlYWUyNmUyKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzZlNjVjNzJmOWI5MjRkYzM4NmI1ZTFkYjA5NTljZGRlID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjY2ODA2LDM5LjYyMDgxNV0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl9lNzIwNjVkMGQ2Y2I0ODU0OGZlN2U5YWE4MzYxZWE3MSA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnZ3JlZW4nLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfNmU2NWM3MmY5YjkyNGRjMzg2YjVlMWRiMDk1OWNkZGUuc2V0SWNvbihpY29uX2U3MjA2NWQwZDZjYjQ4NTQ4ZmU3ZTlhYTgzNjFlYTcxKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2EwZGEzMmQ0NmQwMzRmM2M5YTI3NzI3MTBhMTE0NjY0ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2NmMzA5OTU5YjdhNTQwNDViMjUyOWMxZjkwNTRmMGUwID0gJCgnPGRpdiBpZD0iaHRtbF9jZjMwOTk1OWI3YTU0MDQ1YjI1MjljMWY5MDU0ZjBlMCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0JvQtdGH0LXQsdC90YvQuSDQv9C70Y/QtiDQl9CQ0J4gwqvQodCw0L3QsNGC0L7RgNC40LkgwqvQkdC10LvRi9C1INC90L7Rh9C4wrs8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2EwZGEzMmQ0NmQwMzRmM2M5YTI3NzI3MTBhMTE0NjY0LnNldENvbnRlbnQoaHRtbF9jZjMwOTk1OWI3YTU0MDQ1YjI1MjljMWY5MDU0ZjBlMCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzZlNjVjNzJmOWI5MjRkYzM4NmI1ZTFkYjA5NTljZGRlLmJpbmRQb3B1cChwb3B1cF9hMGRhMzJkNDZkMDM0ZjNjOWEyNzcyNzEwYTExNDY2NCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl8xMWI0ZTE3NGU4OGM0NjU3OGFiMjA2NWUyNTdkNTY2NCA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ0LjY1Mjg4MywzNy45MzIyMzRdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fNmJlZjRmNTFmMDRjNGM5ZmFiMjQwOWJlOWUxOWU5YWEgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JlaWdlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzExYjRlMTc0ZTg4YzQ2NTc4YWIyMDY1ZTI1N2Q1NjY0LnNldEljb24oaWNvbl82YmVmNGY1MWYwNGM0YzlmYWIyNDA5YmU5ZTE5ZTlhYSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8xMjllODYxMWM0ZmU0YmM1OTkwNzJlYWJmMDE4NTZhOCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF85NDE3OGU4MDMyMzY0MWEzYWUzOWFlYjk2ZDYwNzM4MyA9ICQoJzxkaXYgaWQ9Imh0bWxfOTQxNzhlODAzMjM2NDFhM2FlMzlhZWI5NmQ2MDczODMiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2INC00LXRgtGB0LrQvtCz0L4g0L7Qt9C00L7RgNC+0LLQuNGC0LXQu9GM0L3QvtCz0L4g0LvQsNCz0LXRgNGPIMKr0JDQu9GM0LHQsNGC0YDQvtGBwrsg0JrRgNCw0YHQvdC+0LTQsNGA0YHQutC+0LPQviDQutGA0LDQtdCy0L7Qs9C+INCx0LvQsNCz0L7RgtCy0L7RgNC40YLQtdC70YzQvdC+0LPQviDQvtCx0YnQtdGB0YLQstC10L3QvdC+0LPQviDRhNC+0L3QtNCwIMKr0JDQu9GM0LHQsNGC0YDQvtGBwrs8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzEyOWU4NjExYzRmZTRiYzU5OTA3MmVhYmYwMTg1NmE4LnNldENvbnRlbnQoaHRtbF85NDE3OGU4MDMyMzY0MWEzYWUzOWFlYjk2ZDYwNzM4Myk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzExYjRlMTc0ZTg4YzQ2NTc4YWIyMDY1ZTI1N2Q1NjY0LmJpbmRQb3B1cChwb3B1cF8xMjllODYxMWM0ZmU0YmM1OTkwNzJlYWJmMDE4NTZhOCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl83NzhjNzQ0MDcwYmQ0YzA4OGE1MDliMjFmOTlmNGJkYiA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ0LjM1NDIyLDM4LjY2NTY2NF0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl9jNzc0MTZiMTc4ODk0NWYwYmRiMTYzNWI2NDM1NmNhNyA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnZ3JlZW4nLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfNzc4Yzc0NDA3MGJkNGMwODhhNTA5YjIxZjk5ZjRiZGIuc2V0SWNvbihpY29uX2M3NzQxNmIxNzg4OTQ1ZjBiZGIxNjM1YjY0MzU2Y2E3KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzIwMjA0NDcyZDJjZjQxMTNhZTM4ZGUzYzFhNWJiZjBhID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzFlNTZjMzJjZTY4ODQ0ODc5NWIwNDRhYjg3NDcwZTU3ID0gJCgnPGRpdiBpZD0iaHRtbF8xZTU2YzMyY2U2ODg0NDg3OTViMDQ0YWI4NzQ3MGU1NyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYg0KTQk9CR0KMgItCU0L7QvCDQvtGC0LTRi9GF0LAgItCi0YPQsNC/0YHQtSIg0KPQv9GA0LDQstC70LXQvdC40Y8g0LTQtdC70LDQvNC4INCf0YDQtdC30LjQtNC10L3RgtCwINCg0L7RgdGB0LjQudGB0LrQvtC5INCk0LXQtNC10YDQsNGG0LjQuDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMjAyMDQ0NzJkMmNmNDExM2FlMzhkZTNjMWE1YmJmMGEuc2V0Q29udGVudChodG1sXzFlNTZjMzJjZTY4ODQ0ODc5NWIwNDRhYjg3NDcwZTU3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfNzc4Yzc0NDA3MGJkNGMwODhhNTA5YjIxZjk5ZjRiZGIuYmluZFBvcHVwKHBvcHVwXzIwMjA0NDcyZDJjZjQxMTNhZTM4ZGUzYzFhNWJiZjBhKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2VhZWVlMWRmNThmODRkYmRiZGE3MWE1MDhlZGIzMjlmID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuNjQxMjA1LDM3LjkyNzIyMl0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl8wN2I4NGExNWQ4NTk0ZjdiOWJiYTgwNDBiNjJiM2U0MiA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmVpZ2UnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfZWFlZWUxZGY1OGY4NGRiZGJkYTcxYTUwOGVkYjMyOWYuc2V0SWNvbihpY29uXzA3Yjg0YTE1ZDg1OTRmN2I5YmJhODA0MGI2MmIzZTQyKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzgzOGYwOTE5YmQ3MDQyODY4YWI3MjNjN2ZmNzRlZDBmID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2I4OGUxYTRhMzQ5ODQ2NTU5ZGJkN2FjY2YwZTBmZTk5ID0gJCgnPGRpdiBpZD0iaHRtbF9iODhlMWE0YTM0OTg0NjU1OWRiZDdhY2NmMGUwZmU5OSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYg0LHQsNC30Ysg0L7RgtC00YvRhdCwICLQmNGB0LrRgNCwIjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfODM4ZjA5MTliZDcwNDI4NjhhYjcyM2M3ZmY3NGVkMGYuc2V0Q29udGVudChodG1sX2I4OGUxYTRhMzQ5ODQ2NTU5ZGJkN2FjY2YwZTBmZTk5KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfZWFlZWUxZGY1OGY4NGRiZGJkYTcxYTUwOGVkYjMyOWYuYmluZFBvcHVwKHBvcHVwXzgzOGYwOTE5YmQ3MDQyODY4YWI3MjNjN2ZmNzRlZDBmKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2Q5ZTI4N2QwZGM4YjQyMTE4NWJmNzU5ZThjNTIyMWEyID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNjA5OTY4LDM5LjcwNzI5Nl0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl8zODI1YmU3NzgyYjI0ODNkYTEzMTMxZGNkNmFhMDExNSA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl9kOWUyODdkMGRjOGI0MjExODViZjc1OWU4YzUyMjFhMi5zZXRJY29uKGljb25fMzgyNWJlNzc4MmIyNDgzZGExMzEzMWRjZDZhYTAxMTUpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfZjcwMTIxNzc2N2Y2NDk1ZGFmZDEzMDU4NDZjZWYxNTQgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfNTU5ZDQyOTIxNGVkNDJiNmI0ODcwZjI2OGVkNTJlMDYgPSAkKCc8ZGl2IGlkPSJodG1sXzU1OWQ0MjkyMTRlZDQyYjZiNDg3MGYyNjhlZDUyZTA2IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDQpNCT0JHQoyDCq9Ce0LHRitC10LTQuNC90LXQvdC90YvQuSDRgdCw0L3QsNGC0L7RgNC40LkgwqvQoNGD0YHRjMK7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9mNzAxMjE3NzY3ZjY0OTVkYWZkMTMwNTg0NmNlZjE1NC5zZXRDb250ZW50KGh0bWxfNTU5ZDQyOTIxNGVkNDJiNmI0ODcwZjI2OGVkNTJlMDYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9kOWUyODdkMGRjOGI0MjExODViZjc1OWU4YzUyMjFhMi5iaW5kUG9wdXAocG9wdXBfZjcwMTIxNzc2N2Y2NDk1ZGFmZDEzMDU4NDZjZWYxNTQpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfOWRmOGYzZWEzODM5NDZmMDk3NjI1M2MxNmI2NzYxZmYgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC45MzU2ODgsMzcuMzEwNzQ0XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uX2NhZWM0ZjlhY2NiYjRkOTdiYjU2M2JhMThjZGJiNTY4ID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdiZWlnZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl85ZGY4ZjNlYTM4Mzk0NmYwOTc2MjUzYzE2YjY3NjFmZi5zZXRJY29uKGljb25fY2FlYzRmOWFjY2JiNGQ5N2JiNTYzYmExOGNkYmI1NjgpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNTM2NGM2MjUyZmRhNGJjNWI5NzUzYzU2YTU4OWE5NmYgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfNTY4ODM4MThlNjMxNDJjYThmOTk5MGZiMjE5ZjNmNDYgPSAkKCc8ZGl2IGlkPSJodG1sXzU2ODgzODE4ZTYzMTQyY2E4Zjk5OTBmYjIxOWYzZjQ2IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij4g0J/Qu9GP0LYg0KHQsNC90LDRgtC+0YDQuNGPICLQntCz0L7QvdC10LoiIDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNTM2NGM2MjUyZmRhNGJjNWI5NzUzYzU2YTU4OWE5NmYuc2V0Q29udGVudChodG1sXzU2ODgzODE4ZTYzMTQyY2E4Zjk5OTBmYjIxOWYzZjQ2KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfOWRmOGYzZWEzODM5NDZmMDk3NjI1M2MxNmI2NzYxZmYuYmluZFBvcHVwKHBvcHVwXzUzNjRjNjI1MmZkYTRiYzViOTc1M2M1NmE1ODlhOTZmKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzQyYmFjMDc1NzA0MDQ3MWZhZTMwYTNhNjM3NGFiODFjID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuOTczNTI1LDM3LjI3MDU0NF0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl9lM2IzNjQwMmJkZDM0MzZhYWIyY2ViOTllNTk3ODJiYSA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmVpZ2UnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfNDJiYWMwNzU3MDQwNDcxZmFlMzBhM2E2Mzc0YWI4MWMuc2V0SWNvbihpY29uX2UzYjM2NDAyYmRkMzQzNmFhYjJjZWI5OWU1OTc4MmJhKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzM1YThiMWY1ODM0MjRmYzg5MDgwNTQyZjc1ZjhmYWY3ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2I5MWYzOTIwYzA3MjQ4Nzg4MDM3YmJjZDU5OTIzYWJkID0gJCgnPGRpdiBpZD0iaHRtbF9iOTFmMzkyMGMwNzI0ODc4ODAzN2JiY2Q1OTkyM2FiZCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYg0J7QntCeICLQodCw0L3QsNGC0L7RgNC40LkgItCf0LDRgNGD0YEiPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8zNWE4YjFmNTgzNDI0ZmM4OTA4MDU0MmY3NWY4ZmFmNy5zZXRDb250ZW50KGh0bWxfYjkxZjM5MjBjMDcyNDg3ODgwMzdiYmNkNTk5MjNhYmQpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl80MmJhYzA3NTcwNDA0NzFmYWUzMGEzYTYzNzRhYjgxYy5iaW5kUG9wdXAocG9wdXBfMzVhOGIxZjU4MzQyNGZjODkwODA1NDJmNzVmOGZhZjcpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfNjYzMzljZjI5ODg2NDFlYWFjNTdmYTMyOTFjNzFjNTMgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC45NTk5NDgsMzcuMjkxMjk1XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uX2MzOGYzNjVjNGY3YzQ3Y2E4MTc4ODFjNjk4YTQxM2I5ID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdncmVlbicsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl82NjMzOWNmMjk4ODY0MWVhYWM1N2ZhMzI5MWM3MWM1My5zZXRJY29uKGljb25fYzM4ZjM2NWM0ZjdjNDdjYTgxNzg4MWM2OThhNDEzYjkpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYjBlYmMwNmY5OGQ2NDg1MDg5YjVkNDQwNWYwOTIwYjcgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZmM5OGY3MGFhYWI3NGYyNDgwMDA5NzM2OGViNmIxZWQgPSAkKCc8ZGl2IGlkPSJodG1sX2ZjOThmNzBhYWFiNzRmMjQ4MDAwOTczNjhlYjZiMWVkIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDQntCe0J4g0JrQniAi0J7Qu9C40LzQvyI8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2IwZWJjMDZmOThkNjQ4NTA4OWI1ZDQ0MDVmMDkyMGI3LnNldENvbnRlbnQoaHRtbF9mYzk4ZjcwYWFhYjc0ZjI0ODAwMDk3MzY4ZWI2YjFlZCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzY2MzM5Y2YyOTg4NjQxZWFhYzU3ZmEzMjkxYzcxYzUzLmJpbmRQb3B1cChwb3B1cF9iMGViYzA2Zjk4ZDY0ODUwODliNWQ0NDA1ZjA5MjBiNyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl8yNmJlM2MxNTdiNTU0YzliYTMyMzRmNWUwZmRmOWQ0MiA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ0Ljk3MzEzNiwzNy4yNzEwMDJdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fZTNiZDc4NjQxN2Q5NGEwOWJmOTFkMzM3N2E4MzhhMWIgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JlaWdlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzI2YmUzYzE1N2I1NTRjOWJhMzIzNGY1ZTBmZGY5ZDQyLnNldEljb24oaWNvbl9lM2JkNzg2NDE3ZDk0YTA5YmY5MWQzMzc3YTgzOGExYik7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9mZDBkMWZlNzVkNmQ0ZmY5OGFjNWU1MjA5YjY1MGUxYSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF82MjZiMjY3OGRhMWQ0MGE0YjUyNWExM2Y2N2E0N2MyNiA9ICQoJzxkaXYgaWQ9Imh0bWxfNjI2YjI2NzhkYTFkNDBhNGI1MjVhMTNmNjdhNDdjMjYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2INCe0J7QniDCq9Ce0LTQuNGB0YHQtdGPwrs8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2ZkMGQxZmU3NWQ2ZDRmZjk4YWM1ZTUyMDliNjUwZTFhLnNldENvbnRlbnQoaHRtbF82MjZiMjY3OGRhMWQ0MGE0YjUyNWExM2Y2N2E0N2MyNik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzI2YmUzYzE1N2I1NTRjOWJhMzIzNGY1ZTBmZGY5ZDQyLmJpbmRQb3B1cChwb3B1cF9mZDBkMWZlNzVkNmQ0ZmY5OGFjNWU1MjA5YjY1MGUxYSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9mYjZiNTA1NTUwNmY0ZjM3YWEyOTcyNmUxZDIzMzBlZCA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ0LjU3OTgyLDM4LjA2MzM3OV0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl85N2VlMDdkNWU5NTE0NTE3YWY4OWRiYmJmN2QzODFiOCA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl9mYjZiNTA1NTUwNmY0ZjM3YWEyOTcyNmUxZDIzMzBlZC5zZXRJY29uKGljb25fOTdlZTA3ZDVlOTUxNDUxN2FmODlkYmJiZjdkMzgxYjgpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNzFjMThjYjVlMzU4NDg5Njk3MjZkM2ZhYzBiMWFkNTggPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZTAwZDgzOThjYWFlNGE4OWJkNDI3OWNiY2RhZjY2YWMgPSAkKCc8ZGl2IGlkPSJodG1sX2UwMGQ4Mzk4Y2FhZTRhODliZDQyNzljYmNkYWY2NmFjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7QodC/0LXRhtC40LDQu9C40LfQuNGA0L7QstCw0L3QvdGL0Lkg0LvQtdGH0LXQsdC90YvQuSDQv9C70Y/QtiDRgdCw0L3QsNGC0L7RgNC40Y8gItCh0L7Qu9C90LXRh9C90YvQuSDQsdC10YDQtdCzIiAg0JLQntChPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF83MWMxOGNiNWUzNTg0ODk2OTcyNmQzZmFjMGIxYWQ1OC5zZXRDb250ZW50KGh0bWxfZTAwZDgzOThjYWFlNGE4OWJkNDI3OWNiY2RhZjY2YWMpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9mYjZiNTA1NTUwNmY0ZjM3YWEyOTcyNmUxZDIzMzBlZC5iaW5kUG9wdXAocG9wdXBfNzFjMThjYjVlMzU4NDg5Njk3MjZkM2ZhYzBiMWFkNTgpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfMGQ2NmVhOTUyYWNhNDM5N2I1Nzk4ODQ5MGRlNjNiNDYgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC4yNjEzNjUsMzguODYwMTMxXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uX2NhYWRmYjM1MzA4YTRlYWVhZmI5MGUxNDk5NGQzYTFhID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdibHVlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzBkNjZlYTk1MmFjYTQzOTdiNTc5ODg0OTBkZTYzYjQ2LnNldEljb24oaWNvbl9jYWFkZmIzNTMwOGE0ZWFlYWZiOTBlMTQ5OTRkM2ExYSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9mZjUyM2M3YWYwMDE0NjNhODMwOWZmNDc3MjM5NWFiZSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF83Y2I4MGYxMGY1YTY0YmYwYTM1OGMzY2RhYTQwMTMyNCA9ICQoJzxkaXYgaWQ9Imh0bWxfN2NiODBmMTBmNWE2NGJmMGEzNThjM2NkYWE0MDEzMjQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCm0LXQvdGC0YDQsNC70YzQvdGL0Lkg0L/Qu9GP0LYgItCd0L7QstC+0LzQuNGF0LDQudC70L7QstGB0LrQuNC5IjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZmY1MjNjN2FmMDAxNDYzYTgzMDlmZjQ3NzIzOTVhYmUuc2V0Q29udGVudChodG1sXzdjYjgwZjEwZjVhNjRiZjBhMzU4YzNjZGFhNDAxMzI0KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfMGQ2NmVhOTUyYWNhNDM5N2I1Nzk4ODQ5MGRlNjNiNDYuYmluZFBvcHVwKHBvcHVwX2ZmNTIzYzdhZjAwMTQ2M2E4MzA5ZmY0NzcyMzk1YWJlKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzViMzk5MDE1YjQ0YzQ0NDU5YTYxNjc0ZmQwZWJkNGJjID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuNDk3MTEyLDM4LjEzNzAzMl0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl8xMThjNjQzNjBmNGI0NTAwOWQzNWQzN2E3MmNhZWRjNSA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmVpZ2UnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfNWIzOTkwMTViNDRjNDQ0NTlhNjE2NzRmZDBlYmQ0YmMuc2V0SWNvbihpY29uXzExOGM2NDM2MGY0YjQ1MDA5ZDM1ZDM3YTcyY2FlZGM1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzZkYjA0MjM4ZGFkMTQzMzRhYTFmZWZmNGRjYjgzMjVkID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzRiZjU5ZGUyMjU4YTQ5MjM5MjM0MDkxMDMzMmFiOTIzID0gJCgnPGRpdiBpZD0iaHRtbF80YmY1OWRlMjI1OGE0OTIzOTIzNDA5MTAzMzJhYjkyMyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYg0L/QsNC90YHQuNC+0L3QsNGC0LAg0L7RgtC00YvRhdCwICLQrdC90YDQs9C10YLQuNC6IjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNmRiMDQyMzhkYWQxNDMzNGFhMWZlZmY0ZGNiODMyNWQuc2V0Q29udGVudChodG1sXzRiZjU5ZGUyMjU4YTQ5MjM5MjM0MDkxMDMzMmFiOTIzKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfNWIzOTkwMTViNDRjNDQ0NTlhNjE2NzRmZDBlYmQ0YmMuYmluZFBvcHVwKHBvcHVwXzZkYjA0MjM4ZGFkMTQzMzRhYTFmZWZmNGRjYjgzMjVkKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzUzYmZhYmRjYTgzODQ2NGZhMzgyYWQxNGI5YzA0Y2RiID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuOTcxODEyLDM5LjI1MTgyM10sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl9lNDlkOWU4ZDE0MTE0ODEwYmY2Zjc2NWQ1OGZlMDYzNSA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmVpZ2UnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfNTNiZmFiZGNhODM4NDY0ZmEzODJhZDE0YjljMDRjZGIuc2V0SWNvbihpY29uX2U0OWQ5ZThkMTQxMTQ4MTBiZjZmNzY1ZDU4ZmUwNjM1KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzEzOWYyNzY3ZDlmNDQwNzJhYzQ1MDYzNjU5NTk1NDZhID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzUxOTlkNzgwNWY2YTQxOGRhZDkyNDNhYjNmZTE4YWM5ID0gJCgnPGRpdiBpZD0iaHRtbF81MTk5ZDc4MDVmNmE0MThkYWQ5MjQzYWIzZmUxOGFjOSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYg0JDQniAi0KHQsNC90LDRgtC+0YDQuNC5ICLQkNCy0YDQvtGA0LAiPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8xMzlmMjc2N2Q5ZjQ0MDcyYWM0NTA2MzY1OTU5NTQ2YS5zZXRDb250ZW50KGh0bWxfNTE5OWQ3ODA1ZjZhNDE4ZGFkOTI0M2FiM2ZlMThhYzkpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl81M2JmYWJkY2E4Mzg0NjRmYTM4MmFkMTRiOWMwNGNkYi5iaW5kUG9wdXAocG9wdXBfMTM5ZjI3NjdkOWY0NDA3MmFjNDUwNjM2NTk1OTU0NmEpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfMTBlNmFhNTE3ODI5NGM0MTlmMmE4ZmFmZDI5ZWQxZjEgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC45NjY5MzIsMzcuMjc4Mzc3XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uX2EwYjczYjMyOWJjZDRjOGFhMmVlM2YwZGUzYWVjYWFjID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdncmVlbicsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl8xMGU2YWE1MTc4Mjk0YzQxOWYyYThmYWZkMjllZDFmMS5zZXRJY29uKGljb25fYTBiNzNiMzI5YmNkNGM4YWEyZWUzZjBkZTNhZWNhYWMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfOGJhZmJiY2NkMzY0NDM4NGJmNmQ3MDEwMDI5NDMwZWYgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZGQwYTE0YmVmYTA1NGM5MTk1MWNjYWUxNmU4NDc2NDIgPSAkKCc8ZGl2IGlkPSJodG1sX2RkMGExNGJlZmEwNTRjOTE5NTFjY2FlMTZlODQ3NjQyIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7QoNC10LrRgNC10LDRhtC40L7QvdC90YvQuSDQv9C70Y/QtiDQkNC90LDQv9GB0LrQvtC5INC/0LXRgNC10YHRi9C/0Lgg0JEtMS0yLTMg0J7QntCeIMKr0JvQsNC30YPRgNC90YvQuSDQsdC10YDQtdCzwrs8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzhiYWZiYmNjZDM2NDQzODRiZjZkNzAxMDAyOTQzMGVmLnNldENvbnRlbnQoaHRtbF9kZDBhMTRiZWZhMDU0YzkxOTUxY2NhZTE2ZTg0NzY0Mik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzEwZTZhYTUxNzgyOTRjNDE5ZjJhOGZhZmQyOWVkMWYxLmJpbmRQb3B1cChwb3B1cF84YmFmYmJjY2QzNjQ0Mzg0YmY2ZDcwMTAwMjk0MzBlZik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9mYzEzYjc5NmIyYzc0MzExODMwZDBkYzUwNzM5MWZkOSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ0LjMwNjkxOCwzOC43MDQ4NjZdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fNjljOWM1MGU2ODdmNDFmODk5MjNjYjI2NTBkZGNiZmQgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JsdWUnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfZmMxM2I3OTZiMmM3NDMxMTgzMGQwZGM1MDczOTFmZDkuc2V0SWNvbihpY29uXzY5YzljNTBlNjg3ZjQxZjg5OTIzY2IyNjUwZGRjYmZkKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2I0OWU5YmM4MzJlNDRlZTRhZTJlZjBjMGMxOGJhNjk0ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzc3NDg0ZjRkZjRiYzQ3OWFiZmVhMWY2OTYwNTJjOWZhID0gJCgnPGRpdiBpZD0iaHRtbF83NzQ4NGY0ZGY0YmM0NzlhYmZlYTFmNjk2MDUyYzlmYSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0JzRg9C90LjRhtC40L/QsNC70YzQvdGL0Lkg0L/Qu9GP0LYgwqvQlNC20YPQsdCz0LDCuzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYjQ5ZTliYzgzMmU0NGVlNGFlMmVmMGMwYzE4YmE2OTQuc2V0Q29udGVudChodG1sXzc3NDg0ZjRkZjRiYzQ3OWFiZmVhMWY2OTYwNTJjOWZhKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfZmMxM2I3OTZiMmM3NDMxMTgzMGQwZGM1MDczOTFmZDkuYmluZFBvcHVwKHBvcHVwX2I0OWU5YmM4MzJlNDRlZTRhZTJlZjBjMGMxOGJhNjk0KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzEyOTI4OTEyNGFkOTQ0YWJiMjAxOGFlMjg3ZGQ2ZGQyID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNTY2MzM3LDM5LjczOTQ5Ml0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl9jY2Y1ZjJlYjQ2OTE0OTUyOWY1NWE5OWVlYmFhYjU0NCA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl8xMjkyODkxMjRhZDk0NGFiYjIwMThhZTI4N2RkNmRkMi5zZXRJY29uKGljb25fY2NmNWYyZWI0NjkxNDk1MjlmNTVhOTllZWJhYWI1NDQpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMGVhZWNjNWIzMTRlNGM2ZDg4ZTg1ZTdlMzgzZjM0ZWIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMWIzNDFhOWNkMmYxNDJjZmI1YmM5MjMwOGUyNTE4NGMgPSAkKCc8ZGl2IGlkPSJodG1sXzFiMzQxYTljZDJmMTQyY2ZiNWJjOTIzMDhlMjUxODRjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDQu9C10YfQtdCx0L3Ri9C5INC/0LDQvdGB0LjQvtC90LDRgtCwIMKr0K3QtNC10LzCuzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMGVhZWNjNWIzMTRlNGM2ZDg4ZTg1ZTdlMzgzZjM0ZWIuc2V0Q29udGVudChodG1sXzFiMzQxYTljZDJmMTQyY2ZiNWJjOTIzMDhlMjUxODRjKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfMTI5Mjg5MTI0YWQ5NDRhYmIyMDE4YWUyODdkZDZkZDIuYmluZFBvcHVwKHBvcHVwXzBlYWVjYzViMzE0ZTRjNmQ4OGU4NWU3ZTM4M2YzNGViKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2ZlMmY2MzIwZGQ3NzQ5MjE5ZjZkOTIyZWJmOWJiMmZlID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNDgwMTI0LDM5Ljg5MjgyNV0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl8yZTFiY2ViOGMxZDk0MWI0Yjc5MWQ2NWU5ZDE3NjkzZSA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnZ3JlZW4nLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfZmUyZjYzMjBkZDc3NDkyMTlmNmQ5MjJlYmY5YmIyZmUuc2V0SWNvbihpY29uXzJlMWJjZWI4YzFkOTQxYjRiNzkxZDY1ZTlkMTc2OTNlKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzI1MDVlYmEyZjhiMjQ0Yjg5YmE0YTg0MTY0YmQzYTg1ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzdmOTMzYjIzOWVlNTRhYTdiOTBiY2YwMTc2NmY2ZDhmID0gJCgnPGRpdiBpZD0iaHRtbF83ZjkzM2IyMzllZTU0YWE3YjkwYmNmMDE3NjZmNmQ4ZiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYgwqvQl9C90LDQvdC40LXCuyDQntCe0J4gwqvQodCa0JogwqvQl9C90LDQvdC40LXCuzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMjUwNWViYTJmOGIyNDRiODliYTRhODQxNjRiZDNhODUuc2V0Q29udGVudChodG1sXzdmOTMzYjIzOWVlNTRhYTdiOTBiY2YwMTc2NmY2ZDhmKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfZmUyZjYzMjBkZDc3NDkyMTlmNmQ5MjJlYmY5YmIyZmUuYmluZFBvcHVwKHBvcHVwXzI1MDVlYmEyZjhiMjQ0Yjg5YmE0YTg0MTY0YmQzYTg1KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzRjYmRhMGEwM2RjNjRhNjk4N2Q0MjRmNjk2ZjhmNjIwID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDUuMTgxMTk1LDMzLjMxMzUyOF0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl9kNDIyZWI1MzcyM2Q0NzQzOTA1MzA4NDZjNjkyYTdhOCA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl80Y2JkYTBhMDNkYzY0YTY5ODdkNDI0ZjY5NmY4ZjYyMC5zZXRJY29uKGljb25fZDQyMmViNTM3MjNkNDc0MzkwNTMwODQ2YzY5MmE3YTgpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfM2EwY2FmNWM1OGQzNDMxZDgwZTYwMjUwODA3MzVmODggPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZTM3MmYzMDU4ZmRkNDQ5Njg3Nzc2MTNkZjRjYTViOGIgPSAkKCc8ZGl2IGlkPSJodG1sX2UzNzJmMzA1OGZkZDQ0OTY4Nzc3NjEzZGY0Y2E1YjhiIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDCq9Cm0LXQvdGC0YAg0YHQv9C+0YDRgtCwIMKr0K3QstC+0LvRjtGG0LjRj8K7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8zYTBjYWY1YzU4ZDM0MzFkODBlNjAyNTA4MDczNWY4OC5zZXRDb250ZW50KGh0bWxfZTM3MmYzMDU4ZmRkNDQ5Njg3Nzc2MTNkZjRjYTViOGIpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl80Y2JkYTBhMDNkYzY0YTY5ODdkNDI0ZjY5NmY4ZjYyMC5iaW5kUG9wdXAocG9wdXBfM2EwY2FmNWM1OGQzNDMxZDgwZTYwMjUwODA3MzVmODgpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfM2MyZWZlNjU0YjhjNGNlMWE1ZGNkZDVhNzJkZmM2MDMgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC45NDkxNzUsMzcuMjk5Njg2XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uX2QzNTdiNDk4MGQ2ZjQxMjU5MDkzZGRkZTgwMGNmMDRmID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdiZWlnZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl8zYzJlZmU2NTRiOGM0Y2UxYTVkY2RkNWE3MmRmYzYwMy5zZXRJY29uKGljb25fZDM1N2I0OTgwZDZmNDEyNTkwOTNkZGRlODAwY2YwNGYpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMDU2ZDkwM2RiMzc2NGZiZGExMmQ3MTJiYzRiODNkNGIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMmIwZjBlNmI1NzdlNGYwNzhhN2ZlNDVlM2VjMTM3MDkgPSAkKCc8ZGl2IGlkPSJodG1sXzJiMGYwZTZiNTc3ZTRmMDc4YTdmZTQ1ZTNlYzEzNzA5IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDQlNCh0J7QmyDCq9Cj0YDQsNC70YzRgdC60LjQtSDRgdCw0LzQvtGG0LLQtdGC0YvCuyDQntCe0J4gwqvQo9GA0LDQu9GM0YHQutC40LUg0YHQsNC80L7RhtCy0LXRgtGLwrs8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzA1NmQ5MDNkYjM3NjRmYmRhMTJkNzEyYmM0YjgzZDRiLnNldENvbnRlbnQoaHRtbF8yYjBmMGU2YjU3N2U0ZjA3OGE3ZmU0NWUzZWMxMzcwOSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzNjMmVmZTY1NGI4YzRjZTFhNWRjZGQ1YTcyZGZjNjAzLmJpbmRQb3B1cChwb3B1cF8wNTZkOTAzZGIzNzY0ZmJkYTEyZDcxMmJjNGI4M2Q0Yik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl83OWQ0ODhiZGRlZjg0ZWFlODA0NzJjZWE5OWE1ZDIyNyA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ0Ljk1NzY5MSwzNy4yOTI3MjRdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fZGEyMWVjNjg1OTE0NDRiMWExMzVkYWU1NzQ3ZDQzNTAgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2dyZWVuJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzc5ZDQ4OGJkZGVmODRlYWU4MDQ3MmNlYTk5YTVkMjI3LnNldEljb24oaWNvbl9kYTIxZWM2ODU5MTQ0NGIxYTEzNWRhZTU3NDdkNDM1MCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9mMGRlNTRjNDZmNDE0OThiYmQzZTM1ODAwMjA0NjA1NSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF82MDNlODA0ZGRiNTU0ZjgxYWE2YTFlYmZhOTQ3ZWE0NSA9ICQoJzxkaXYgaWQ9Imh0bWxfNjAzZTgwNGRkYjU1NGY4MWFhNmExZWJmYTk0N2VhNDUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCg0LXQutGA0LXQsNGG0LjQvtC90L3Ri9C5INC/0LvRj9C2INCQ0L3QsNC/0YHQutC+0Lkg0L/QtdGA0LXRgdGL0L/QuCDQlC0xLTQtODwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZjBkZTU0YzQ2ZjQxNDk4YmJkM2UzNTgwMDIwNDYwNTUuc2V0Q29udGVudChodG1sXzYwM2U4MDRkZGI1NTRmODFhYTZhMWViZmE5NDdlYTQ1KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfNzlkNDg4YmRkZWY4NGVhZTgwNDcyY2VhOTlhNWQyMjcuYmluZFBvcHVwKHBvcHVwX2YwZGU1NGM0NmY0MTQ5OGJiZDNlMzU4MDAyMDQ2MDU1KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzE1OTk1ZmUyYTM5MjQzZWY4MTFlNzg4NDA2NWY0NTkwID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuOTA4NjA4LDM3LjMyMzM2NV0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl80ZTE3YTUwNTRhOWQ0ZTY2ODlmMDNmNWM3ZDRhMjM4OCA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmVpZ2UnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfMTU5OTVmZTJhMzkyNDNlZjgxMWU3ODg0MDY1ZjQ1OTAuc2V0SWNvbihpY29uXzRlMTdhNTA1NGE5ZDRlNjY4OWYwM2Y1YzdkNGEyMzg4KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzI1NGRlMzQ2ZDkzNDQ3YTQ4OWE3YTVjMzE5ODZlMWI4ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzUyMzhlZGUwYmM2NDRjOGJiNDVlOTYyMTU5NmM3YjAwID0gJCgnPGRpdiBpZD0iaHRtbF81MjM4ZWRlMGJjNjQ0YzhiYjQ1ZTk2MjE1OTZjN2IwMCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYg0KHQntCaIMKr0KHQv9GD0YLQvdC40LrCuyAtINCk0LjQu9C40LDQu9CwINCk0JPQkdCj0JogwqvQk9CQ0JHQoiDQoNC+0YHRgdC40LjCuzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMjU0ZGUzNDZkOTM0NDdhNDg5YTdhNWMzMTk4NmUxYjguc2V0Q29udGVudChodG1sXzUyMzhlZGUwYmM2NDRjOGJiNDVlOTYyMTU5NmM3YjAwKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfMTU5OTVmZTJhMzkyNDNlZjgxMWU3ODg0MDY1ZjQ1OTAuYmluZFBvcHVwKHBvcHVwXzI1NGRlMzQ2ZDkzNDQ3YTQ4OWE3YTVjMzE5ODZlMWI4KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2UyZmYyMDgyYjBkNjQ3MjA5MDgwZWE0NmEwODQxZmFlID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuNjUyODgzLDM3LjkzMjIzNF0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl9iNjZhYTNlZDRlYWY0YmExOTQ5ZWZkYjg3NjEzOTJkMSA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmVpZ2UnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfZTJmZjIwODJiMGQ2NDcyMDkwODBlYTQ2YTA4NDFmYWUuc2V0SWNvbihpY29uX2I2NmFhM2VkNGVhZjRiYTE5NDllZmRiODc2MTM5MmQxKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzA0MDU3Y2M2Zjg0ZDQ0NzU4OWVlNWM0ZDgyYWFmMjk4ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzQxNzJkOGU5ZWQwNjQ1OTZiM2VhZWI1ZDA0MjQyNzAxID0gJCgnPGRpdiBpZD0iaHRtbF80MTcyZDhlOWVkMDY0NTk2YjNlYWViNWQwNDI0MjcwMSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYg0JTQntCbIMKr0KHQuNCz0L3QsNC7wrs8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzA0MDU3Y2M2Zjg0ZDQ0NzU4OWVlNWM0ZDgyYWFmMjk4LnNldENvbnRlbnQoaHRtbF80MTcyZDhlOWVkMDY0NTk2YjNlYWViNWQwNDI0MjcwMSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyX2UyZmYyMDgyYjBkNjQ3MjA5MDgwZWE0NmEwODQxZmFlLmJpbmRQb3B1cChwb3B1cF8wNDA1N2NjNmY4NGQ0NDc1ODllZTVjNGQ4MmFhZjI5OCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9hYTY1MzA0Yzc0MzM0YjgwODI5YzdjYzZmNWJiMTFiNSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ0LjU3MjEyMiwzOC4wNzk1MDRdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fMTgwZjI2YjZiZjUzNDcwZmE0MDkxYTUxOWFkNGNkZmYgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JlaWdlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyX2FhNjUzMDRjNzQzMzRiODA4MjljN2NjNmY1YmIxMWI1LnNldEljb24oaWNvbl8xODBmMjZiNmJmNTM0NzBmYTQwOTFhNTE5YWQ0Y2RmZik7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9lMjE2Y2I0YTNmZmM0NTQ2OTQ1YzBjZWI3MzBhZDQ3NiA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8wOTUzMjQ4YWFjNTE0NzUxYTkxYjAwYmUzYTU3MWUyYiA9ICQoJzxkaXYgaWQ9Imh0bWxfMDk1MzI0OGFhYzUxNDc1MWE5MWIwMGJlM2E1NzFlMmIiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2INGB0LDQvdCw0YLQvtGA0LjRjyDCq9CX0LLQtdC30LTQvtGH0LrQsMK7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9lMjE2Y2I0YTNmZmM0NTQ2OTQ1YzBjZWI3MzBhZDQ3Ni5zZXRDb250ZW50KGh0bWxfMDk1MzI0OGFhYzUxNDc1MWE5MWIwMGJlM2E1NzFlMmIpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9hYTY1MzA0Yzc0MzM0YjgwODI5YzdjYzZmNWJiMTFiNS5iaW5kUG9wdXAocG9wdXBfZTIxNmNiNGEzZmZjNDU0Njk0NWMwY2ViNzMwYWQ0NzYpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfYWU2NWM4Y2QxZGUyNDFkMTk1NDBiOGEzOGRmNWMyY2EgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NS4zNDc1OTksMzcuMTI3NDUyXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uX2M0NDY2MWY2NTI1OTQyNWZhMTA4MjAyMmQ1ZTkyZDVhID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdiZWlnZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl9hZTY1YzhjZDFkZTI0MWQxOTU0MGI4YTM4ZGY1YzJjYS5zZXRJY29uKGljb25fYzQ0NjYxZjY1MjU5NDI1ZmExMDgyMDIyZDVlOTJkNWEpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfY2U5ZmI1OGNjOTMxNDc4NmE5NDUwZjBlNmI5MTQxNzcgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZGZiZDNjNGUxNzNmNGJiZThiMmY4NzhkZjU0OWFjZDggPSAkKCc8ZGl2IGlkPSJodG1sX2RmYmQzYzRlMTczZjRiYmU4YjJmODc4ZGY1NDlhY2Q4IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDQntCe0J4gwqvQl9C+0LvQvtGC0L7QuSDQv9C70Y/QtsK7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9jZTlmYjU4Y2M5MzE0Nzg2YTk0NTBmMGU2YjkxNDE3Ny5zZXRDb250ZW50KGh0bWxfZGZiZDNjNGUxNzNmNGJiZThiMmY4NzhkZjU0OWFjZDgpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9hZTY1YzhjZDFkZTI0MWQxOTU0MGI4YTM4ZGY1YzJjYS5iaW5kUG9wdXAocG9wdXBfY2U5ZmI1OGNjOTMxNDc4NmE5NDUwZjBlNmI5MTQxNzcpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfYTdiMDZhODc0MDc1NDZhYTk5MjI5OTVmYTdiM2JiMzAgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC4zMDA0MzUsMzguNzU0OTM4XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uX2YxNzE3NWUwZmNiYjQ1ODQ4OWI5ZjJhMmQzNjViOWFhID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdibHVlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyX2E3YjA2YTg3NDA3NTQ2YWE5OTIyOTk1ZmE3YjNiYjMwLnNldEljb24oaWNvbl9mMTcxNzVlMGZjYmI0NTg0ODliOWYyYTJkMzY1YjlhYSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9jZGYxZTNhZTRhNDA0NTgyOWNiZGViN2RhZDExMzZkZiA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF81NTFhZGFkNzVjOWY0ZTg0ODhlMjRhODVjNGZmMjQxYSA9ICQoJzxkaXYgaWQ9Imh0bWxfNTUxYWRhZDc1YzlmNGU4NDg4ZTI0YTg1YzRmZjI0MWEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2INGB0LDQvdCw0YLQvtGA0LjRjyDCq9Cb0LXRgNC80L7QvdGC0L7QstC+wrsg0J7QkNCeIMKr0KHRg9GA0LPRg9GC0L3QtdGE0YLQtdCz0LDQt8K7INCe0KIgwqvQodGD0YDQs9GD0YLCuzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfY2RmMWUzYWU0YTQwNDU4MjljYmRlYjdkYWQxMTM2ZGYuc2V0Q29udGVudChodG1sXzU1MWFkYWQ3NWM5ZjRlODQ4OGUyNGE4NWM0ZmYyNDFhKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfYTdiMDZhODc0MDc1NDZhYTk5MjI5OTVmYTdiM2JiMzAuYmluZFBvcHVwKHBvcHVwX2NkZjFlM2FlNGE0MDQ1ODI5Y2JkZWI3ZGFkMTEzNmRmKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2QwOTAzYmE3OTc2MTQ0ODU5YTY2OTcwMDJlNTllZjg5ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuMTgwNzE3LDM4Ljk3NDI5OF0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl9mOWY0MzQ1Zjc3ZmM0NDRmOGQ4MzIzNTc4ZDA5YmQxYiA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl9kMDkwM2JhNzk3NjE0NDg1OWE2Njk3MDAyZTU5ZWY4OS5zZXRJY29uKGljb25fZjlmNDM0NWY3N2ZjNDQ0ZjhkODMyMzU3OGQwOWJkMWIpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMTBhZmRlODkzNzZmNGVhMjhlZjdkZjgzMjQ4NDAwNGQgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMTIxY2IyNjQ4ZDkzNDMzNjg2OTY2YjUwNGI5OGE1ZTggPSAkKCc8ZGl2IGlkPSJodG1sXzEyMWNiMjY0OGQ5MzQzMzY4Njk2NmI1MDRiOThhNWU4IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDRgdCw0L3QsNGC0L7RgNC40Y8gwqvQndC10YTRgtGP0L3QuNC6INCh0LjQsdC40YDQuMK7INCe0JDQniDCq9Ch0YPRgNCz0YPRgtC90LXRhNGC0LXQs9Cw0LfCuyDQntCiIMKr0KHRg9GA0LPRg9GCwrs8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzEwYWZkZTg5Mzc2ZjRlYTI4ZWY3ZGY4MzI0ODQwMDRkLnNldENvbnRlbnQoaHRtbF8xMjFjYjI2NDhkOTM0MzM2ODY5NjZiNTA0Yjk4YTVlOCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyX2QwOTAzYmE3OTc2MTQ0ODU5YTY2OTcwMDJlNTllZjg5LmJpbmRQb3B1cChwb3B1cF8xMGFmZGU4OTM3NmY0ZWEyOGVmN2RmODMyNDg0MDA0ZCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9mMTFmYjFiZDcyMWY0ZGIwYjFkM2Q2NTI4MjgwZDY5NSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ0LjI3Nzk5OSwzOC44MDg5MzZdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fNzEyMTZiNWNmNDQwNGJlZThkNDEwMjhmYmRkZmQ2ZDEgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JlaWdlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyX2YxMWZiMWJkNzIxZjRkYjBiMWQzZDY1MjgyODBkNjk1LnNldEljb24oaWNvbl83MTIxNmI1Y2Y0NDA0YmVlOGQ0MTAyOGZiZGRmZDZkMSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9hMjgzMDYxMGRlMTk0ZDUyODFhYzc2YzJiZTk3NmE4NCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9kZjExMDg4OTBlYTc0NTE3OWFiYjg4OWM4YTQ0MDgwMSA9ICQoJzxkaXYgaWQ9Imh0bWxfZGYxMTA4ODkwZWE3NDUxNzlhYmI4ODljOGE0NDA4MDEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2INC00LXRgtGB0LrQvtCz0L4g0YHQsNC90LDRgtC+0YDQuNGPIMKr0K7QvdGL0Lkg0L3QtdGE0YLRj9C90LjQusK7INCe0JDQniDCq9Ch0YPRgNCz0YPRgtC90LXRhNGC0LXQs9Cw0LfCuyDQntCiIMKr0KHRg9GA0LPRg9GCwrs8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2EyODMwNjEwZGUxOTRkNTI4MWFjNzZjMmJlOTc2YTg0LnNldENvbnRlbnQoaHRtbF9kZjExMDg4OTBlYTc0NTE3OWFiYjg4OWM4YTQ0MDgwMSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyX2YxMWZiMWJkNzIxZjRkYjBiMWQzZDY1MjgyODBkNjk1LmJpbmRQb3B1cChwb3B1cF9hMjgzMDYxMGRlMTk0ZDUyODFhYzc2YzJiZTk3NmE4NCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl8zZmI0Y2U3ODE3ODg0ZmZjYWRhYjRiZjU2M2FhZTYwMSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ0LjkyMzA2NiwzNy4zMjEyMzZdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fMDZhZTRlYThjYzgwNDJkMzgxZThhNGNmOTA3ZmQ5NGMgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JlaWdlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzNmYjRjZTc4MTc4ODRmZmNhZGFiNGJmNTYzYWFlNjAxLnNldEljb24oaWNvbl8wNmFlNGVhOGNjODA0MmQzODFlOGE0Y2Y5MDdmZDk0Yyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF83OGIxZWFlMDlkNzA0YmUzOGQ3NDU4YzNiYmI2NTkxYSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9iZjY4ZGQ4ZDc2MGQ0YTI0ODE5MDc1YTVkZGFiMzg2ZSA9ICQoJzxkaXYgaWQ9Imh0bWxfYmY2OGRkOGQ3NjBkNGEyNDgxOTA3NWE1ZGRhYjM4NmUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2INCk0LjQu9C40LDQu9CwINCb0J7QmiDCq9CX0LLQtdC30LTQvtGH0LrQsCAtINCu0LPCuyDQkNCeIMKr0KbQoSDCq9CX0LLQtdC30LTQvtGH0LrQsMK7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF83OGIxZWFlMDlkNzA0YmUzOGQ3NDU4YzNiYmI2NTkxYS5zZXRDb250ZW50KGh0bWxfYmY2OGRkOGQ3NjBkNGEyNDgxOTA3NWE1ZGRhYjM4NmUpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl8zZmI0Y2U3ODE3ODg0ZmZjYWRhYjRiZjU2M2FhZTYwMS5iaW5kUG9wdXAocG9wdXBfNzhiMWVhZTA5ZDcwNGJlMzhkNzQ1OGMzYmJiNjU5MWEpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfOTNmYTNlYjY4YWIwNGE1YTliZmU2NWZjMTcxNTUwYzYgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC45Njg5NjYsMzcuMjgyOTIzXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uX2Q3ZDkwMzQwYWI5ZjQ5NThiNTRkMmRkNjJkYzFhZTk0ID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdiZWlnZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl85M2ZhM2ViNjhhYjA0YTVhOWJmZTY1ZmMxNzE1NTBjNi5zZXRJY29uKGljb25fZDdkOTAzNDBhYjlmNDk1OGI1NGQyZGQ2MmRjMWFlOTQpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNzc4NmZkMmUyYjQzNGRiY2IzYTg1MTA2YjMxMWNiMWEgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfNjYzZTBkZjRmZDE4NDllMWJiZjk2ZTIzOGExZTgxMDggPSAkKCc8ZGl2IGlkPSJodG1sXzY2M2UwZGY0ZmQxODQ5ZTFiYmY5NmUyMzhhMWU4MTA4IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDQodCe0JogwqvQkNC90LDQv9CwLdCd0LXQv9GC0YPQvcK7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF83Nzg2ZmQyZTJiNDM0ZGJjYjNhODUxMDZiMzExY2IxYS5zZXRDb250ZW50KGh0bWxfNjYzZTBkZjRmZDE4NDllMWJiZjk2ZTIzOGExZTgxMDgpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl85M2ZhM2ViNjhhYjA0YTVhOWJmZTY1ZmMxNzE1NTBjNi5iaW5kUG9wdXAocG9wdXBfNzc4NmZkMmUyYjQzNGRiY2IzYTg1MTA2YjMxMWNiMWEpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfNDBhNGJkYjdkOTczNDY4NWI2YzMyMzBiZTk5YTEwNmIgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC4yNTM4NDQsMzkuMTM3NzczXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uXzEzMjA4YjNmNWFlYzRiNDhhOTFhNGEwZGM2NjVmZmM3ID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdiZWlnZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl80MGE0YmRiN2Q5NzM0Njg1YjZjMzIzMGJlOTlhMTA2Yi5zZXRJY29uKGljb25fMTMyMDhiM2Y1YWVjNGI0OGE5MWE0YTBkYzY2NWZmYzcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNzM4ODE3NjllNDI0NDhkNzllYzBhNGJkYTM0NjQ0ZTIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZTQ5M2M4ZGM3ZmFkNDYzNjg4MDE3MDlmZWM4MGY4ZGIgPSAkKCc8ZGl2IGlkPSJodG1sX2U0OTNjOGRjN2ZhZDQ2MzY4ODAxNzA5ZmVjODBmOGRiIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDRgdCw0L3QsNGC0L7RgNC40Y8gwqvQl9C+0YDRjNC60LDCuyDQl9CQ0J4gwqvQodCw0L3QsNGC0L7RgNC40LkgwqvQl9C+0YDRjNC60LDCuzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNzM4ODE3NjllNDI0NDhkNzllYzBhNGJkYTM0NjQ0ZTIuc2V0Q29udGVudChodG1sX2U0OTNjOGRjN2ZhZDQ2MzY4ODAxNzA5ZmVjODBmOGRiKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfNDBhNGJkYjdkOTczNDY4NWI2YzMyMzBiZTk5YTEwNmIuYmluZFBvcHVwKHBvcHVwXzczODgxNzY5ZTQyNDQ4ZDc5ZWMwYTRiZGEzNDY0NGUyKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzc4ZGUzZWNlY2YxZjRiNmY4ZjljNmFiYTc1NzBkZWEwID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuMjAxMzM2LDM4Ljg4OTE2NV0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl8zOWNiOTRjM2EyODg0NjIzYWE0NzQzMWEzNDBiYjMyZCA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnZ3JlZW4nLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfNzhkZTNlY2VjZjFmNGI2ZjhmOWM2YWJhNzU3MGRlYTAuc2V0SWNvbihpY29uXzM5Y2I5NGMzYTI4ODQ2MjNhYTQ3NDMxYTM0MGJiMzJkKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzhhZDE3NmJkM2ViZjQxYTk4YTcxNDI0NjM3OTA5MzY0ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2M1ODA4YzBhM2JmNjQzZDNiYTg3MDM3NGM5MzJjOTA4ID0gJCgnPGRpdiBpZD0iaHRtbF9jNTgwOGMwYTNiZjY0M2QzYmE4NzAzNzRjOTMyYzkwOCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0JTQtdGC0YHQutC40Lkg0L/Qu9GP0LYg0J8v0J4g0KHQotCa0JQgwqvQqNCw0YXRgtC40L3RgdC60LjQuSDRgtC10LrRgdGC0LjQu9GM0YnQuNC6wrs8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzhhZDE3NmJkM2ViZjQxYTk4YTcxNDI0NjM3OTA5MzY0LnNldENvbnRlbnQoaHRtbF9jNTgwOGMwYTNiZjY0M2QzYmE4NzAzNzRjOTMyYzkwOCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzc4ZGUzZWNlY2YxZjRiNmY4ZjljNmFiYTc1NzBkZWEwLmJpbmRQb3B1cChwb3B1cF84YWQxNzZiZDNlYmY0MWE5OGE3MTQyNDYzNzkwOTM2NCk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl85NDc2YTA1MWI2YmY0N2QwOThiMDg4ODcxYTc3ZTE3MSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ0LjYzMzcyLDM3LjkwODg3OF0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl8xODZlNjA0YTUxMWQ0YTVlODJlZmM1ZDg2NTM0MmEzMCA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl85NDc2YTA1MWI2YmY0N2QwOThiMDg4ODcxYTc3ZTE3MS5zZXRJY29uKGljb25fMTg2ZTYwNGE1MTFkNGE1ZTgyZWZjNWQ4NjUzNDJhMzApOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNGYyNTljY2NiMWZkNGJhZmI0ZDVhZWQ2MTJjZWU2MmMgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYWVkMjY1MTA3N2M2NGE2ZWI3ZTA3MGVkNjg5ZTZlYjQgPSAkKCc8ZGl2IGlkPSJodG1sX2FlZDI2NTEwNzdjNjRhNmViN2UwNzBlZDY4OWU2ZWI0IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDQmtGD0YDQvtGA0YLQvdC+0LPQviDQutC+0LzQv9C70LXQutGB0LAg0J3QsNC00LXQttC00LAgU1BBJtCc0L7RgNGB0LrQvtC5INCg0LDQuTwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNGYyNTljY2NiMWZkNGJhZmI0ZDVhZWQ2MTJjZWU2MmMuc2V0Q29udGVudChodG1sX2FlZDI2NTEwNzdjNjRhNmViN2UwNzBlZDY4OWU2ZWI0KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfOTQ3NmEwNTFiNmJmNDdkMDk4YjA4ODg3MWE3N2UxNzEuYmluZFBvcHVwKHBvcHVwXzRmMjU5Y2NjYjFmZDRiYWZiNGQ1YWVkNjEyY2VlNjJjKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzI2YjI1NDI5YjNmYzQ1MGNiNDUxZDY4NDAyNzY0MTMzID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuNDk0NDQ0LDM4LjEzNTQ5Nl0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl8zNGY5ZWU4MjgxNDg0MzU2OTIzZWIxOGRmN2EzNWI4NiA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmVpZ2UnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfMjZiMjU0MjliM2ZjNDUwY2I0NTFkNjg0MDI3NjQxMzMuc2V0SWNvbihpY29uXzM0ZjllZTgyODE0ODQzNTY5MjNlYjE4ZGY3YTM1Yjg2KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzNlZDE1OWMzM2M5OTQyYmRiNTNiM2M2NGI5ZDA2ZTU4ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2JkOWQ4ZWU0Yzg3ZjQ3ODE5ZDhhMTI5ZDNjNjg1MmE3ID0gJCgnPGRpdiBpZD0iaHRtbF9iZDlkOGVlNGM4N2Y0NzgxOWQ4YTEyOWQzYzY4NTJhNyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0JvQtdGH0LXQsdC90YvQuSDQv9C70Y/QtiDRgdCw0L3QsNGC0L7RgNC40Y8gItCT0L7Qu9GD0LHQsNGPINC00LDQu9GMIjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfM2VkMTU5YzMzYzk5NDJiZGI1M2IzYzY0YjlkMDZlNTguc2V0Q29udGVudChodG1sX2JkOWQ4ZWU0Yzg3ZjQ3ODE5ZDhhMTI5ZDNjNjg1MmE3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfMjZiMjU0MjliM2ZjNDUwY2I0NTFkNjg0MDI3NjQxMzMuYmluZFBvcHVwKHBvcHVwXzNlZDE1OWMzM2M5OTQyYmRiNTNiM2M2NGI5ZDA2ZTU4KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2Y0ODg5MDNiNjBmZDQ4YjJhNDk4ODg2YjNkZTIwM2FiID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuNjU5Mjk0LDM3LjkyMTEzMV0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl81YjI0MWQ2YzRkZTU0ZTFkOGZkOGQ3OTMyNWZkN2Q3NiA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmVpZ2UnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfZjQ4ODkwM2I2MGZkNDhiMmE0OTg4ODZiM2RlMjAzYWIuc2V0SWNvbihpY29uXzViMjQxZDZjNGRlNTRlMWQ4ZmQ4ZDc5MzI1ZmQ3ZDc2KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzI2ZWRkMDY4ZTA5NzQwZWJiYzQ4ZGJmMmRhMDg1MTgyID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2ZlM2UxZTZhYWUzYzQzZjU5OTdhZWRlYjRmZjBjNTI1ID0gJCgnPGRpdiBpZD0iaHRtbF9mZTNlMWU2YWFlM2M0M2Y1OTk3YWVkZWI0ZmYwYzUyNSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYg0L/QsNC90YHQuNC+0L3QsNGC0LAgwqvQmtCw0LHQsNGA0LTQuNC90LrQsMK7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8yNmVkZDA2OGUwOTc0MGViYmM0OGRiZjJkYTA4NTE4Mi5zZXRDb250ZW50KGh0bWxfZmUzZTFlNmFhZTNjNDNmNTk5N2FlZGViNGZmMGM1MjUpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9mNDg4OTAzYjYwZmQ0OGIyYTQ5ODg4NmIzZGUyMDNhYi5iaW5kUG9wdXAocG9wdXBfMjZlZGQwNjhlMDk3NDBlYmJjNDhkYmYyZGEwODUxODIpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfOWMzZDk0NDk1ZmIzNGE0ZWFjZTc2Y2M2ZThkOTE5YTIgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC44OTI3MjQsMzcuMzI0NDM0XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uXzVhMWVlMGQwZmRjODQ4ZGY5MDQwYTdkYmIwZDUzYjc3ID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdibHVlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzljM2Q5NDQ5NWZiMzRhNGVhY2U3NmNjNmU4ZDkxOWEyLnNldEljb24oaWNvbl81YTFlZTBkMGZkYzg0OGRmOTA0MGE3ZGJiMGQ1M2I3Nyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8wNDlmNDU2Njc3OTI0ZDI4ODExMjE4YjgzMWM3MjAyZCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9hNGI0ZDU2YmI3YmU0MDdhYTcxM2ZmNTFmN2FlZTYxZCA9ICQoJzxkaXYgaWQ9Imh0bWxfYTRiNGQ1NmJiN2JlNDA3YWE3MTNmZjUxZjdhZWU2MWQiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2INGB0LDQvdCw0YLQvtGA0LjRjyAi0JDQvdCw0L/QsCIg0JDQniDCq9Ch0LDQvdCw0YLQvtGA0LjQuSDCq9CQ0L3QsNC/0LDCuzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMDQ5ZjQ1NjY3NzkyNGQyODgxMTIxOGI4MzFjNzIwMmQuc2V0Q29udGVudChodG1sX2E0YjRkNTZiYjdiZTQwN2FhNzEzZmY1MWY3YWVlNjFkKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfOWMzZDk0NDk1ZmIzNGE0ZWFjZTc2Y2M2ZThkOTE5YTIuYmluZFBvcHVwKHBvcHVwXzA0OWY0NTY2Nzc5MjRkMjg4MTEyMThiODMxYzcyMDJkKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2YwMTFjOGY1ZjhhZjQyZTJiM2I4ODMyNTdhMTY1YjVlID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuNjA2ODgyLDMzLjQ4NDAzN10sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl9hMTA2NzllODc1ZDc0YzE1YjVmNjdjOWMxNjdlZmU3NSA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl9mMDExYzhmNWY4YWY0MmUyYjNiODgzMjU3YTE2NWI1ZS5zZXRJY29uKGljb25fYTEwNjc5ZTg3NWQ3NGMxNWI1ZjY3YzljMTY3ZWZlNzUpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfODdkZmM5ODFiZTVjNGUwZTkwYThiZjljMTUyMDI0N2YgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfOTE1MmEzZjRmNGE5NDAyMWI0YTYxNDkxODM5NjAzNTEgPSAkKCc8ZGl2IGlkPSJodG1sXzkxNTJhM2Y0ZjRhOTQwMjFiNGE2MTQ5MTgzOTYwMzUxIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDCq9Cf0LXRgdC+0YfQvdCw0Y8g0LHRg9GF0YLQsMK7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF84N2RmYzk4MWJlNWM0ZTBlOTBhOGJmOWMxNTIwMjQ3Zi5zZXRDb250ZW50KGh0bWxfOTE1MmEzZjRmNGE5NDAyMWI0YTYxNDkxODM5NjAzNTEpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9mMDExYzhmNWY4YWY0MmUyYjNiODgzMjU3YTE2NWI1ZS5iaW5kUG9wdXAocG9wdXBfODdkZmM5ODFiZTVjNGUwZTkwYThiZjljMTUyMDI0N2YpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfZjkyZmIwMDE3ZjNhNDY2ZjlmYWI4MzZlNDAzY2JlMGEgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC40OTg1NTMsMzQuMTgwNDM4XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uXzcwZTcxYzUwMzg3NjRkMzVhYzRhYTNkYzU1MmY3ZDM3ID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdibHVlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyX2Y5MmZiMDAxN2YzYTQ2NmY5ZmFiODM2ZTQwM2NiZTBhLnNldEljb24oaWNvbl83MGU3MWM1MDM4NzY0ZDM1YWM0YWEzZGM1NTJmN2QzNyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF82ZTZkODk3OWU4MDI0MjgwYTQzMTUwZGJiZWI3N2VkMCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF83ZmIwYWY3ZGZlODk0NTBiYTM1Y2E5NTdjMjNiMWIyYyA9ICQoJzxkaXYgaWQ9Imh0bWxfN2ZiMGFmN2RmZTg5NDUwYmEzNWNhOTU3YzIzYjFiMmMiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPsKr0JzQsNGB0YHQsNC90LTRgNC+0LLRgdC60LjQuSDQv9C70Y/QtsK7INCe0J7QniDCq9CY0JvQktCY0JDCuzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNmU2ZDg5NzllODAyNDI4MGE0MzE1MGRiYmViNzdlZDAuc2V0Q29udGVudChodG1sXzdmYjBhZjdkZmU4OTQ1MGJhMzVjYTk1N2MyM2IxYjJjKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfZjkyZmIwMDE3ZjNhNDY2ZjlmYWI4MzZlNDAzY2JlMGEuYmluZFBvcHVwKHBvcHVwXzZlNmQ4OTc5ZTgwMjQyODBhNDMxNTBkYmJlYjc3ZWQwKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzRmYTljY2U2NGJiMjRmZTJhYzE3MjkzZDcxMzc3YTA3ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuNDg5MjI5LDM0LjE2Mjc0Ml0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl84MTFkYzRiMTMzZjM0YzYzYTdkMDRkMDAzMjFlYjVhYyA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl80ZmE5Y2NlNjRiYjI0ZmUyYWMxNzI5M2Q3MTM3N2EwNy5zZXRJY29uKGljb25fODExZGM0YjEzM2YzNGM2M2E3ZDA0ZDAwMzIxZWI1YWMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfY2YzYjAzZWU1YjE3NDljNmFjNWQzY2Y3MzI2M2E4YTcgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMTFiYWViMDg0YTlmNDYwN2E1MTBhNDkwMjZiN2Q5ZGEgPSAkKCc8ZGl2IGlkPSJodG1sXzExYmFlYjA4NGE5ZjQ2MDdhNTEwYTQ5MDI2YjdkOWRhIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDCq9Ch0J/QkC3QntGC0LXQu9GMIMKr0J/RgNC40LzQvtGA0YHQutC40Lkg0L/QsNGA0LrCuyDQntCe0J4gwqvQptC10L3RgtGA0LjQvdCy0LXRgdGCwrs8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2NmM2IwM2VlNWIxNzQ5YzZhYzVkM2NmNzMyNjNhOGE3LnNldENvbnRlbnQoaHRtbF8xMWJhZWIwODRhOWY0NjA3YTUxMGE0OTAyNmI3ZDlkYSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzRmYTljY2U2NGJiMjRmZTJhYzE3MjkzZDcxMzc3YTA3LmJpbmRQb3B1cChwb3B1cF9jZjNiMDNlZTViMTc0OWM2YWM1ZDNjZjczMjYzYThhNyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9jZjI3OWJlNTAxOWU0ZmYyOGU1MjE1YjVkNmRlZmM0MCA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ0LjkxNzY2LDM3LjMyNjA2OV0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl9hM2MxMmU3ZTM1YWE0NTIyOTJjNDVhYjNhMTkyMzFiMSA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl9jZjI3OWJlNTAxOWU0ZmYyOGU1MjE1YjVkNmRlZmM0MC5zZXRJY29uKGljb25fYTNjMTJlN2UzNWFhNDUyMjkyYzQ1YWIzYTE5MjMxYjEpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfM2IyNDY1NzQ0NzNhNDlkMWJjMTAyOWJlY2RlZThjMzUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfODZlOTA3NDg1MTlkNDBmYmE4ZWY4YzAxODc0MzE0NzEgPSAkKCc8ZGl2IGlkPSJodG1sXzg2ZTkwNzQ4NTE5ZDQwZmJhOGVmOGMwMTg3NDMxNDcxIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij4g0J/Qu9GP0LYg0J7QntCeIMKr0JLQuNC60YLQvtGA0LjRj8K7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8zYjI0NjU3NDQ3M2E0OWQxYmMxMDI5YmVjZGVlOGMzNS5zZXRDb250ZW50KGh0bWxfODZlOTA3NDg1MTlkNDBmYmE4ZWY4YzAxODc0MzE0NzEpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9jZjI3OWJlNTAxOWU0ZmYyOGU1MjE1YjVkNmRlZmM0MC5iaW5kUG9wdXAocG9wdXBfM2IyNDY1NzQ0NzNhNDlkMWJjMTAyOWJlY2RlZThjMzUpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfN2I0OThhMDU0NTJlNDk1MzhmYWRkZjYzZDAyZjc0ZDUgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC45MzE1ODUsMzcuMzE3MDMyXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uX2VhOTBmN2Q2Yzg2ZTQyNmFiZTVkMDIxMTEwYjU2NDgzID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdibHVlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzdiNDk4YTA1NDUyZTQ5NTM4ZmFkZGY2M2QwMmY3NGQ1LnNldEljb24oaWNvbl9lYTkwZjdkNmM4NmU0MjZhYmU1ZDAyMTExMGI1NjQ4Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8xOTRkMDk3MjJmOWE0YWMxYmZhYThhOTJmNTk3NDRmZCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8zOTZlOGE1NmNlMjk0MmM3YjYxZTQwYmFhN2QxNWM0ZiA9ICQoJzxkaXYgaWQ9Imh0bWxfMzk2ZThhNTZjZTI5NDJjN2I2MWU0MGJhYTdkMTVjNGYiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2INCe0J7QniDCq9Cf0LDQvdGB0LjQvtC90LDRgiDCq9Cj0YDQvtC20LDQucK7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8xOTRkMDk3MjJmOWE0YWMxYmZhYThhOTJmNTk3NDRmZC5zZXRDb250ZW50KGh0bWxfMzk2ZThhNTZjZTI5NDJjN2I2MWU0MGJhYTdkMTVjNGYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl83YjQ5OGEwNTQ1MmU0OTUzOGZhZGRmNjNkMDJmNzRkNS5iaW5kUG9wdXAocG9wdXBfMTk0ZDA5NzIyZjlhNGFjMWJmYWE4YTkyZjU5NzQ0ZmQpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfYjYxMzlhNzkwNGRjNGJlNzhkMDIyOTFiZmEyOTVjMzAgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0My40MTQ2MjgsMzkuOTI2NDRdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fZDZhMTg0MWE4ZjUwNGMxOGFjYTE0YWNmOTMwMWIxMGQgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JsdWUnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfYjYxMzlhNzkwNGRjNGJlNzhkMDIyOTFiZmEyOTVjMzAuc2V0SWNvbihpY29uX2Q2YTE4NDFhOGY1MDRjMThhY2ExNGFjZjkzMDFiMTBkKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2ExOTg4Nzc3YjExNDRlYzhiMjMzYTdkYjhlYzNjZTViID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2I3YTlhZTRhYTg5ZTRkZGM5MmU1OWQwZWExY2E0MDllID0gJCgnPGRpdiBpZD0iaHRtbF9iN2E5YWU0YWE4OWU0ZGRjOTJlNTlkMGVhMWNhNDA5ZSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYg0LPQvtGB0YLQuNC90LjRhtGLICLQmtGD0YDQvtGA0YLQvdGL0Lkg0LrQvtC80L/Qu9C10LrRgSDQuCDQutC+0L3Qs9GA0LXRgdGBLdGG0LXQvdGC0YAg0KDRjdC00LjRgdGB0L7QvSDQkdC70YMsINCh0L7Rh9C4IjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYTE5ODg3NzdiMTE0NGVjOGIyMzNhN2RiOGVjM2NlNWIuc2V0Q29udGVudChodG1sX2I3YTlhZTRhYTg5ZTRkZGM5MmU1OWQwZWExY2E0MDllKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfYjYxMzlhNzkwNGRjNGJlNzhkMDIyOTFiZmEyOTVjMzAuYmluZFBvcHVwKHBvcHVwX2ExOTg4Nzc3YjExNDRlYzhiMjMzYTdkYjhlYzNjZTViKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzgwNzZhOTI1MjBmNDRiM2ZiNTQ4YTU0YTE0MWYzN2YyID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuNjUzOTAyLDM0LjM5OTg1Ml0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl9lM2UzYjZjYmE3NzM0ZGYzYWQ3ZWI1OTBlOGZmZWZmMyA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnZ3JlZW4nLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfODA3NmE5MjUyMGY0NGIzZmI1NDhhNTRhMTQxZjM3ZjIuc2V0SWNvbihpY29uX2UzZTNiNmNiYTc3MzRkZjNhZDdlYjU5MGU4ZmZlZmYzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2Q4ZTY2YzVmMzk0MjRhZTA4NWZkZmJjZjY4MjFjYTkzID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzIyMWQ3Yjc4ZGYyZjQzNGRhOGRkYTc1OWM5M2FhYjE4ID0gJCgnPGRpdiBpZD0iaHRtbF8yMjFkN2I3OGRmMmY0MzRkYThkZGE3NTljOTNhYWIxOCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYg0J7QntCeICLQkNC60LLQsNGC0LXRhdC90L7RgdC/0L7RgNGCIjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfZDhlNjZjNWYzOTQyNGFlMDg1ZmRmYmNmNjgyMWNhOTMuc2V0Q29udGVudChodG1sXzIyMWQ3Yjc4ZGYyZjQzNGRhOGRkYTc1OWM5M2FhYjE4KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfODA3NmE5MjUyMGY0NGIzZmI1NDhhNTRhMTQxZjM3ZjIuYmluZFBvcHVwKHBvcHVwX2Q4ZTY2YzVmMzk0MjRhZTA4NWZkZmJjZjY4MjFjYTkzKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzNmNjVjMThkZjNkYTQ2OWM5YmM1YjY3MjBjYjE0MzhlID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuOTA3Njk2LDM3LjMyMDk0XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uX2FlMDVhYmRjNTQ0YjQzMjBiZGJmNDkwMGQ4OTM4ODhkID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdncmVlbicsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl8zZjY1YzE4ZGYzZGE0NjljOWJjNWI2NzIwY2IxNDM4ZS5zZXRJY29uKGljb25fYWUwNWFiZGM1NDRiNDMyMGJkYmY0OTAwZDg5Mzg4OGQpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNGQ2Yjg4NjAxOGY5NGJmYjhhYWUzZWY3ZjBiZTA3MmEgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfNmE5OGEwMDkxMTFmNDI3M2I1MWE4ZDQzNzExMTYzMjcgPSAkKCc8ZGl2IGlkPSJodG1sXzZhOThhMDA5MTExZjQyNzNiNTFhOGQ0MzcxMTE2MzI3IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDQvtGC0LXQu9GPICLQodCw0L3QvNCw0YDQuNC90L0iPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF80ZDZiODg2MDE4Zjk0YmZiOGFhZTNlZjdmMGJlMDcyYS5zZXRDb250ZW50KGh0bWxfNmE5OGEwMDkxMTFmNDI3M2I1MWE4ZDQzNzExMTYzMjcpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl8zZjY1YzE4ZGYzZGE0NjljOWJjNWI2NzIwY2IxNDM4ZS5iaW5kUG9wdXAocG9wdXBfNGQ2Yjg4NjAxOGY5NGJmYjhhYWUzZWY3ZjBiZTA3MmEpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfOWIzMjk0MTQxZmQ5NDA4NGIwN2JkYzA3YjYyYTc1YzcgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC41NzE0MTYsMzguMDcxMjEzXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uXzdjYTljMjEzNzY2OTQzMzE5NjZiZGY3Yzg1ZGY5ZDI5ID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdncmVlbicsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl85YjMyOTQxNDFmZDk0MDg0YjA3YmRjMDdiNjJhNzVjNy5zZXRJY29uKGljb25fN2NhOWMyMTM3NjY5NDMzMTk2NmJkZjdjODVkZjlkMjkpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYTg3OWNhMDhhM2NhNDQ3MWIyN2IyZmNmOGZhOGYzZmMgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfM2YyNDFkM2RmZWUyNDIyOTk3NDhiN2QzNDcyOTJkZTMgPSAkKCc8ZGl2IGlkPSJodG1sXzNmMjQxZDNkZmVlMjQyMjk5NzQ4YjdkMzQ3MjkyZGUzIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDRgdCw0L3QsNGC0L7RgNC40Y8g0LjQvC4g0Jwu0JIuINCb0L7QvNC+0L3QvtGB0L7QstCwPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9hODc5Y2EwOGEzY2E0NDcxYjI3YjJmY2Y4ZmE4ZjNmYy5zZXRDb250ZW50KGh0bWxfM2YyNDFkM2RmZWUyNDIyOTk3NDhiN2QzNDcyOTJkZTMpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl85YjMyOTQxNDFmZDk0MDg0YjA3YmRjMDdiNjJhNzVjNy5iaW5kUG9wdXAocG9wdXBfYTg3OWNhMDhhM2NhNDQ3MWIyN2IyZmNmOGZhOGYzZmMpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfNDRjNjVkYThjZDRhNGI0YjgwNDQyMDBmNDQ0ZjY0MTYgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC40MDg5ODcsMzMuOTQxMjUzXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uXzU5YzcxMGZlNmYzMTQzM2VhOGM1NGMzNDFmNDVjMTM4ID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdibHVlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzQ0YzY1ZGE4Y2Q0YTRiNGI4MDQ0MjAwZjQ0NGY2NDE2LnNldEljb24oaWNvbl81OWM3MTBmZTZmMzE0MzNlYThjNTRjMzQxZjQ1YzEzOCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8yODExMTJjNmY2M2E0N2JlOTRlYTkyN2RiNTVlZjNiNyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF80YzM3MDBmMjk5OWM0OGE3OTUwOGYyMDc0NWJjN2FjZCA9ICQoJzxkaXYgaWQ9Imh0bWxfNGMzNzAwZjI5OTljNDhhNzk1MDhmMjA3NDViYzdhY2QiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2INCc0YDQuNGPINCg0LXQt9C+0YDRgiAmINCh0L/QsDwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMjgxMTEyYzZmNjNhNDdiZTk0ZWE5MjdkYjU1ZWYzYjcuc2V0Q29udGVudChodG1sXzRjMzcwMGYyOTk5YzQ4YTc5NTA4ZjIwNzQ1YmM3YWNkKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfNDRjNjVkYThjZDRhNGI0YjgwNDQyMDBmNDQ0ZjY0MTYuYmluZFBvcHVwKHBvcHVwXzI4MTExMmM2ZjYzYTQ3YmU5NGVhOTI3ZGI1NWVmM2I3KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2M0YmY5NWQ3YzNmNjRiYmVhZDEzNTUyOTFmZDdkYjNjID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuODk3MTY4LDM3LjMwMzc3M10sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl8yNThhNWJkYTQ4NTQ0MTU3OWI1N2Y5ZTc2ZTBmZjIyYyA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl9jNGJmOTVkN2MzZjY0YmJlYWQxMzU1MjkxZmQ3ZGIzYy5zZXRJY29uKGljb25fMjU4YTViZGE0ODU0NDE1NzliNTdmOWU3NmUwZmYyMmMpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfOTQzNThiZjQ1NzEwNDRiZjg4NGE4ZmU0MmI0ZmUyYzcgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfYzk4ZWVlOGNmZmIxNGVmNmI0ODRlYmY5ZmQzY2QzNjggPSAkKCc8ZGl2IGlkPSJodG1sX2M5OGVlZThjZmZiMTRlZjZiNDg0ZWJmOWZkM2NkMzY4IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Cq9Cb0LXRh9C10LHQvdGL0Lkg0L/Qu9GP0LYgwqvQl9C+0LvQvtGC0LDRjyDQsdGD0YXRgtCwwrsg0J7QntCeIMKr0JfQvtC70L7RgtCw0Y8g0LHRg9GF0YLQsMK7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF85NDM1OGJmNDU3MTA0NGJmODg0YThmZTQyYjRmZTJjNy5zZXRDb250ZW50KGh0bWxfYzk4ZWVlOGNmZmIxNGVmNmI0ODRlYmY5ZmQzY2QzNjgpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9jNGJmOTVkN2MzZjY0YmJlYWQxMzU1MjkxZmQ3ZGIzYy5iaW5kUG9wdXAocG9wdXBfOTQzNThiZjQ1NzEwNDRiZjg4NGE4ZmU0MmI0ZmUyYzcpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfZDZkNmEwYTkzMzg0NDhlMjg3ZmY0ZjIzYjQ5NTA0YWQgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC4zMjIzOTcsMzguNzA0MzYzXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uXzYzYTYwZmI1MzkwNzQxZDdiZWIzNDU5MWY5ZGM4NDg3ID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdiZWlnZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl9kNmQ2YTBhOTMzODQ0OGUyODdmZjRmMjNiNDk1MDRhZC5zZXRJY29uKGljb25fNjNhNjBmYjUzOTA3NDFkN2JlYjM0NTkxZjlkYzg0ODcpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfOGVhNTE2YTQwYmU0NDFiNjliMWY0NmI4NGFlZTM5MmYgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfY2Q5M2M5ZmM3NTdjNDgzZDgzMzk4NmU0MzM2ZjhkNTggPSAkKCc8ZGl2IGlkPSJodG1sX2NkOTNjOWZjNzU3YzQ4M2Q4MzM5ODZlNDMzNmY4ZDU4IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDQlNCh0J7QmyDCq9Cc0LXRh9GC0LDCuyAg0J3QsNC40LzQtdC90L7QstCw0L3QuNC1INGB0L7QsdGB0YLQstC10L3QvdC40LrQsDog0L7QsdGJ0LXRgdGC0LLQviDRgSDQvtCz0YDQsNC90LjRh9C10L3QvdC+0Lkg0L7RgtCy0LXRgtGB0YLQstC10L3QvdC+0YHRgtGM0Y4g0LTQtdGC0YHQutC40Lkg0YHQsNC90LDRgtC+0YDQvdC+LdC+0LfQtNC+0YDQvtCy0LjRgtC10LvRjNC90YvQuSDQu9Cw0LPQtdGA0YwgwqvQnNC10YfRgtCwwrs8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzhlYTUxNmE0MGJlNDQxYjY5YjFmNDZiODRhZWUzOTJmLnNldENvbnRlbnQoaHRtbF9jZDkzYzlmYzc1N2M0ODNkODMzOTg2ZTQzMzZmOGQ1OCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyX2Q2ZDZhMGE5MzM4NDQ4ZTI4N2ZmNGYyM2I0OTUwNGFkLmJpbmRQb3B1cChwb3B1cF84ZWE1MTZhNDBiZTQ0MWI2OWIxZjQ2Yjg0YWVlMzkyZik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl80MWQ3NDYxYTYxMTU0MDFkYWQ0NzRlY2Q5MThiMTU0MyA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ0LjQ5OTc2OCwzOC4xMzczMTFdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fZjRjZjk2YTQxMzA1NDI5YzgwZDFjMzQyNTQ5NTJiNjMgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JlaWdlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzQxZDc0NjFhNjExNTQwMWRhZDQ3NGVjZDkxOGIxNTQzLnNldEljb24oaWNvbl9mNGNmOTZhNDEzMDU0MjljODBkMWMzNDI1NDk1MmI2Myk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8zNzQwYTRjMzJlZDM0MWQ5YTAxYmRhNWNhODIwNmQ3ZSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8xOGI2M2RlOGE4ZmQ0N2ZlOWRlNmMwYWJjMmVkZDY5MyA9ICQoJzxkaXYgaWQ9Imh0bWxfMThiNjNkZThhOGZkNDdmZTlkZTZjMGFiYzJlZGQ2OTMiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCm0LXQvdGC0YDQsNC70YzQvdGL0Lkg0L/Qu9GP0LYg0YHQtdC70LAg0JTQuNCy0L3QvtC80L7RgNGB0LrQvtC1PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8zNzQwYTRjMzJlZDM0MWQ5YTAxYmRhNWNhODIwNmQ3ZS5zZXRDb250ZW50KGh0bWxfMThiNjNkZThhOGZkNDdmZTlkZTZjMGFiYzJlZGQ2OTMpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl80MWQ3NDYxYTYxMTU0MDFkYWQ0NzRlY2Q5MThiMTU0My5iaW5kUG9wdXAocG9wdXBfMzc0MGE0YzMyZWQzNDFkOWEwMWJkYTVjYTgyMDZkN2UpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfNTVhNWMzYzJmZDViNGU4ZmJiODUyZGFmODkxMGM3M2UgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC4wNjU2MzIsMzkuMTI4MzY4XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uX2Y3NWQ4NGRlZTEyNTQ3MGM5ZjIzZGZmMjZiNTkyZTQxID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdiZWlnZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl81NWE1YzNjMmZkNWI0ZThmYmI4NTJkYWY4OTEwYzczZS5zZXRJY29uKGljb25fZjc1ZDg0ZGVlMTI1NDcwYzlmMjNkZmYyNmI1OTJlNDEpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYTViYTFkYjc1NDhkNDYyZGE4MjA2MjZjOGI1ZDdhODIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfNmQyYjRmNDEzMDJlNDQ0MzgyMjZkZjI3Yzc4NWRmODkgPSAkKCc8ZGl2IGlkPSJodG1sXzZkMmI0ZjQxMzAyZTQ0NDM4MjI2ZGYyN2M3ODVkZjg5IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDQntCe0J4gwqvQn9Cw0L3RgdC40L7QvdCw0YIg0K7QttC90YvQucK7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9hNWJhMWRiNzU0OGQ0NjJkYTgyMDYyNmM4YjVkN2E4Mi5zZXRDb250ZW50KGh0bWxfNmQyYjRmNDEzMDJlNDQ0MzgyMjZkZjI3Yzc4NWRmODkpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl81NWE1YzNjMmZkNWI0ZThmYmI4NTJkYWY4OTEwYzczZS5iaW5kUG9wdXAocG9wdXBfYTViYTFkYjc1NDhkNDYyZGE4MjA2MjZjOGI1ZDdhODIpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfYzMyNzg0MTg0MjcyNDExYjhmM2U4OTJiYWIyODE5YjIgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0My42MDU2OTIsMzkuNzE1NjQyXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uXzYwYTEyYWJhOGM5YzQ0NDNhZGNkZTEzODkzNzFjNzZhID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdibHVlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyX2MzMjc4NDE4NDI3MjQxMWI4ZjNlODkyYmFiMjgxOWIyLnNldEljb24oaWNvbl82MGExMmFiYThjOWM0NDQzYWRjZGUxMzg5MzcxYzc2YSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8xZjg5ZmYxMzA3YWM0ZDYwYjE2ZGYyNDdlODY3NmI1MyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8wNjEzOTdjMWM1ZWE0N2EzYWE5NjEwNGI0ZjA1M2E5OSA9ICQoJzxkaXYgaWQ9Imh0bWxfMDYxMzk3YzFjNWVhNDdhM2FhOTYxMDRiNGYwNTNhOTkiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2INGB0LDQvdCw0YLQvtGA0LjRjyDCq9CX0LDQv9C+0LvRj9GA0YzQtcK7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF8xZjg5ZmYxMzA3YWM0ZDYwYjE2ZGYyNDdlODY3NmI1My5zZXRDb250ZW50KGh0bWxfMDYxMzk3YzFjNWVhNDdhM2FhOTYxMDRiNGYwNTNhOTkpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl9jMzI3ODQxODQyNzI0MTFiOGYzZTg5MmJhYjI4MTliMi5iaW5kUG9wdXAocG9wdXBfMWY4OWZmMTMwN2FjNGQ2MGIxNmRmMjQ3ZTg2NzZiNTMpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfMGI2Zjc2MmY5MTQ4NDRmNGIzZDcyNTg0NTE4YmU0MzIgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC45OTA3MjYsMzcuMjQ5NTUxXSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uX2E5ZTNjNTU0YTc4MDQ3NTM5NzYwMGUwNjNjMzUwNGJjID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdibHVlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzBiNmY3NjJmOTE0ODQ0ZjRiM2Q3MjU4NDUxOGJlNDMyLnNldEljb24oaWNvbl9hOWUzYzU1NGE3ODA0NzUzOTc2MDBlMDYzYzM1MDRiYyk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8xYzViYzgxNWQwMzQ0NTRhODIwMjc2N2VkNWFlMGZkNyA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF82MTg1YTQ4NzIzMjM0YTM5OTUzZjM2NmJhYzU5MWUyNyA9ICQoJzxkaXYgaWQ9Imh0bWxfNjE4NWE0ODcyMzIzNGEzOTk1M2YzNjZiYWM1OTFlMjciIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2ICLQm9Ce0JogItCS0LjRgtGP0LfRjCIg0J7QntCeICLQm9Ce0JogItCS0LjRgtGP0LfRjCI8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzFjNWJjODE1ZDAzNDQ1NGE4MjAyNzY3ZWQ1YWUwZmQ3LnNldENvbnRlbnQoaHRtbF82MTg1YTQ4NzIzMjM0YTM5OTUzZjM2NmJhYzU5MWUyNyk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzBiNmY3NjJmOTE0ODQ0ZjRiM2Q3MjU4NDUxOGJlNDMyLmJpbmRQb3B1cChwb3B1cF8xYzViYzgxNWQwMzQ0NTRhODIwMjc2N2VkNWFlMGZkNyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9jMzk3YmNlM2E5ZDg0NTdkYWFkYTI4NzFjYWM1ODNlYSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjYxMzk2MiwzOS43MTEzMzldLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fNWViZGE1MTdjYzU2NDA1MmE5MTEzNzQ2ZWFkYjQzNzkgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JsdWUnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfYzM5N2JjZTNhOWQ4NDU3ZGFhZGEyODcxY2FjNTgzZWEuc2V0SWNvbihpY29uXzVlYmRhNTE3Y2M1NjQwNTJhOTExMzc0NmVhZGI0Mzc5KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzRiNWY5NTAwYTQzYzRlZWY4MWM3NmZjNTQ0NGQ3NjhiID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzkxMTUwMTZmNmNmMTRiMDI4ZjM4OGM2YTkyZDYyYjExID0gJCgnPGRpdiBpZD0iaHRtbF85MTE1MDE2ZjZjZjE0YjAyOGYzODhjNmE5MmQ2MmIxMSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYg0YHQsNC90LDRgtC+0YDQuNGPICLQkdC10LvQsNGA0YPRgdGMIjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNGI1Zjk1MDBhNDNjNGVlZjgxYzc2ZmM1NDQ0ZDc2OGIuc2V0Q29udGVudChodG1sXzkxMTUwMTZmNmNmMTRiMDI4ZjM4OGM2YTkyZDYyYjExKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfYzM5N2JjZTNhOWQ4NDU3ZGFhZGEyODcxY2FjNTgzZWEuYmluZFBvcHVwKHBvcHVwXzRiNWY5NTAwYTQzYzRlZWY4MWM3NmZjNTQ0NGQ3NjhiKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzVmNTZhNjczOTc0MzRhZDdhZjBiMjdhMjE5Njc5ZTRiID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuNDEwMjEsMzMuOTA4MTVdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fNmJmYzhkODQ1ODFmNDNmNmE1OGNhY2YzMjc5YmM0NDMgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JsdWUnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfNWY1NmE2NzM5NzQzNGFkN2FmMGIyN2EyMTk2NzllNGIuc2V0SWNvbihpY29uXzZiZmM4ZDg0NTgxZjQzZjZhNThjYWNmMzI3OWJjNDQzKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzUwZWFiNjRjYzdjNjQzMDg4NTBjZmZiMGU1NjgwYjg5ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzMwODM1M2VhNzc3MzRkNmE4NTE5MDdkYzQ0Zjc4MzYyID0gJCgnPGRpdiBpZD0iaHRtbF8zMDgzNTNlYTc3NzM0ZDZhODUxOTA3ZGM0NGY3ODM2MiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYg0JrRgNGL0LzRgdC60LjQuSDQsdGA0LjQtzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNTBlYWI2NGNjN2M2NDMwODg1MGNmZmIwZTU2ODBiODkuc2V0Q29udGVudChodG1sXzMwODM1M2VhNzc3MzRkNmE4NTE5MDdkYzQ0Zjc4MzYyKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfNWY1NmE2NzM5NzQzNGFkN2FmMGIyN2EyMTk2NzllNGIuYmluZFBvcHVwKHBvcHVwXzUwZWFiNjRjYzdjNjQzMDg4NTBjZmZiMGU1NjgwYjg5KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzgxMmY1MTEwM2E3YzRjNWRiMWM2MzhhNjE4MjY1YWRhID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuNDg2MTE3LDM0LjE2MDE0NV0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl82NmM2ZGRkYWU1N2M0MjRlYjZkZjk5ODY1NzQ1ZTU3OCA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl84MTJmNTExMDNhN2M0YzVkYjFjNjM4YTYxODI2NWFkYS5zZXRJY29uKGljb25fNjZjNmRkZGFlNTdjNDI0ZWI2ZGY5OTg2NTc0NWU1NzgpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfMjIyYjk3NWMxMGMwNGY3YTg5OWM0NjFiNmVlM2MxNmYgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfY2VhMGFmOWU4OTYxNDE1MTllNGFhZWM2MDQwNmE4ZGUgPSAkKCc8ZGl2IGlkPSJodG1sX2NlYTBhZjllODk2MTQxNTE5ZTRhYWVjNjA0MDZhOGRlIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDRjdC60L4t0L7RgtC10LvRjyDCq9Cb0LXQstCw0L3RgsK7INCe0J7QniAgwqvQo9CaIMKr0JrRgNCw0YHQvtGC0LXQu9GMwrs8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzIyMmI5NzVjMTBjMDRmN2E4OTljNDYxYjZlZTNjMTZmLnNldENvbnRlbnQoaHRtbF9jZWEwYWY5ZTg5NjE0MTUxOWU0YWFlYzYwNDA2YThkZSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzgxMmY1MTEwM2E3YzRjNWRiMWM2MzhhNjE4MjY1YWRhLmJpbmRQb3B1cChwb3B1cF8yMjJiOTc1YzEwYzA0ZjdhODk5YzQ2MWI2ZWUzYzE2Zik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9kM2Y2YTlmNjM3ODM0MzMxYmRmMzk4MTllMGRmNDEyMyA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjU2NDk3OCwzOS43NDQxMzZdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fZmNhOWMwYTA4OTIzNGYzOGE4NTc3M2NhYzQ4YzQzYjAgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JsdWUnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfZDNmNmE5ZjYzNzgzNDMzMWJkZjM5ODE5ZTBkZjQxMjMuc2V0SWNvbihpY29uX2ZjYTljMGEwODkyMzRmMzhhODU3NzNjYWM0OGM0M2IwKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwX2E5NjY1MGQzMGI3MjQ1Y2NiMDAwYzEzMmNkNzA2YzI2ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzgxODJkMGY1MjA0YzQwNTJiNDQ1M2RjYzZkMmFlMTNjID0gJCgnPGRpdiBpZD0iaHRtbF84MTgyZDBmNTIwNGM0MDUyYjQ0NTNkY2M2ZDJhZTEzYyIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYg0YHQsNC90LDRgtC+0YDQuNGPIMKr0JDQstCw0L3Qs9Cw0YDQtMK7IC0gINGE0LjQu9C40LDQu9CwINCk0JPQkdCjIMKr0JTQtdGC0YHQutC40Lkg0LzQtdC00LjRhtC40L3RgdC60LjQuSDRhtC10L3RgtGAwrsg0KPQv9GA0LDQstC70LXQvdC40Y8g0LTQtdC70LDQvNC4INCf0YDQtdC30LjQtNC10L3RgtCwINCg0KQ8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2E5NjY1MGQzMGI3MjQ1Y2NiMDAwYzEzMmNkNzA2YzI2LnNldENvbnRlbnQoaHRtbF84MTgyZDBmNTIwNGM0MDUyYjQ0NTNkY2M2ZDJhZTEzYyk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyX2QzZjZhOWY2Mzc4MzQzMzFiZGYzOTgxOWUwZGY0MTIzLmJpbmRQb3B1cChwb3B1cF9hOTY2NTBkMzBiNzI0NWNjYjAwMGMxMzJjZDcwNmMyNik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl8wZGQ4NDcxNDhlZDI0YjJiOGRiMTVjMWZmNjIyZTY0ZCA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ0Ljk0NzE3OCwzNy4zMDIyOTFdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fZjA1ZTI1NjU1ZWQ1NDY4NWFmZWYyZTJiZTE3NGNlYWQgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JsdWUnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfMGRkODQ3MTQ4ZWQyNGIyYjhkYjE1YzFmZjYyMmU2NGQuc2V0SWNvbihpY29uX2YwNWUyNTY1NWVkNTQ2ODVhZmVmMmUyYmUxNzRjZWFkKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzZkNjhjMmJmZjkzNzQ1ZDViMWY5M2YxMjkwYzk3OThmID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2NhZGM3YWZmZWEyNTQzNWVhYTRkYTE3MjU2MDE0NTViID0gJCgnPGRpdiBpZD0iaHRtbF9jYWRjN2FmZmVhMjU0MzVlYWE0ZGExNzI1NjAxNDU1YiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LYgItCh0LDQvdCw0YLQvtGA0LjRjyAi0K3Qu9C70LDQtNCwIiDQpNCd0KEg0KDQvtGB0YHQuNC4IjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNmQ2OGMyYmZmOTM3NDVkNWIxZjkzZjEyOTBjOTc5OGYuc2V0Q29udGVudChodG1sX2NhZGM3YWZmZWEyNTQzNWVhYTRkYTE3MjU2MDE0NTViKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfMGRkODQ3MTQ4ZWQyNGIyYjhkYjE1YzFmZjYyMmU2NGQuYmluZFBvcHVwKHBvcHVwXzZkNjhjMmJmZjkzNzQ1ZDViMWY5M2YxMjkwYzk3OThmKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2YxNmViYTZmNzFmMDQ0ZThiMjcyYjQ4NTdiMGQ3YjI2ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNDY0MjkyLDM5Ljg5ODEwN10sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl8zZDI5YzIyYWM2MmY0MjlmYmE3MzMwNzZiNzNlMzY5NiA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl9mMTZlYmE2ZjcxZjA0NGU4YjI3MmI0ODU3YjBkN2IyNi5zZXRJY29uKGljb25fM2QyOWMyMmFjNjJmNDI5ZmJhNzMzMDc2YjczZTM2OTYpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYjk1NTE1MGE5ODNjNDAxZGI2ODRkMTUyYzlhYmRjM2MgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfN2JiYzFmNTQ1ZTBiNDA1YmJiMWJmN2Y0OTBmZjY4MmYgPSAkKCc8ZGl2IGlkPSJodG1sXzdiYmMxZjU0NWUwYjQwNWJiYjFiZjdmNDkwZmY2ODJmIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiAi0JLQtdGB0L3QsCIgINCX0JDQniDQodCf0JAt0L7RgtC10LvRjCAi0JLQtdGB0L3QsCI8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwX2I5NTUxNTBhOTgzYzQwMWRiNjg0ZDE1MmM5YWJkYzNjLnNldENvbnRlbnQoaHRtbF83YmJjMWY1NDVlMGI0MDViYmIxYmY3ZjQ5MGZmNjgyZik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyX2YxNmViYTZmNzFmMDQ0ZThiMjcyYjQ4NTdiMGQ3YjI2LmJpbmRQb3B1cChwb3B1cF9iOTU1MTUwYTk4M2M0MDFkYjY4NGQxNTJjOWFiZGMzYyk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl8xOTlmNjkwZTY1YTc0YmQzYWQyZWYwODIyOGNhNWQwNSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjY3MjMwMywzOS42MDY4Ml0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl8yNGM4YTdjYWMyODk0MTRmOWJiZWM0ZDQyZTMxZTdkNSA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl8xOTlmNjkwZTY1YTc0YmQzYWQyZWYwODIyOGNhNWQwNS5zZXRJY29uKGljb25fMjRjOGE3Y2FjMjg5NDE0ZjliYmVjNGQ0MmUzMWU3ZDUpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNThiZGE2YzMxNjk1NGMzYzg3ZGJkMTYwYjFjMWY1MTEgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZWQ4Mjc2ZTQ3ZDI2NDBjMmJjMDEzNWQ5NjIzZmZjZmMgPSAkKCc8ZGl2IGlkPSJodG1sX2VkODI3NmU0N2QyNjQwYzJiYzAxMzVkOTYyM2ZmY2ZjIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDRgdCw0L3QsNGC0L7RgNC40Y8gwqvQmNCy0YPRiNC60LDCuzwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNThiZGE2YzMxNjk1NGMzYzg3ZGJkMTYwYjFjMWY1MTEuc2V0Q29udGVudChodG1sX2VkODI3NmU0N2QyNjQwYzJiYzAxMzVkOTYyM2ZmY2ZjKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfMTk5ZjY5MGU2NWE3NGJkM2FkMmVmMDgyMjhjYTVkMDUuYmluZFBvcHVwKHBvcHVwXzU4YmRhNmMzMTY5NTRjM2M4N2RiZDE2MGIxYzFmNTExKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzUzNWJkZDExZGRjNzQ2N2E5MTQwNDZlNWI1ZmVhMTdlID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDMuNDg3MDk3LDM5Ljg5MjQ2Nl0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl8zYjE2YmYxYTVlOTI0NTA4OTYwMmNhNjEwYmQyYTQ4MCA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl81MzViZGQxMWRkYzc0NjdhOTE0MDQ2ZTViNWZlYTE3ZS5zZXRJY29uKGljb25fM2IxNmJmMWE1ZTkyNDUwODk2MDJjYTYxMGJkMmE0ODApOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfYWZjNWEyZTA3N2ZmNDkzOWE4Mjk1ODE2MDk3MjEzZDggPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfMTEzNzU3ZWVhMzBjNGU1MWE5ZjFiYjY3OGIyMTNmMGYgPSAkKCc8ZGl2IGlkPSJodG1sXzExMzc1N2VlYTMwYzRlNTFhOWYxYmI2NzhiMjEzZjBmIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDQvtC30LTQvtGA0L7QstC40YLQtdC70YzQvdC+0LPQviDQvtCx0YrQtdC00LjQvdC10L3QuNGPIMKr0K7QttC90YvQucK7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9hZmM1YTJlMDc3ZmY0OTM5YTgyOTU4MTYwOTcyMTNkOC5zZXRDb250ZW50KGh0bWxfMTEzNzU3ZWVhMzBjNGU1MWE5ZjFiYjY3OGIyMTNmMGYpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl81MzViZGQxMWRkYzc0NjdhOTE0MDQ2ZTViNWZlYTE3ZS5iaW5kUG9wdXAocG9wdXBfYWZjNWEyZTA3N2ZmNDkzOWE4Mjk1ODE2MDk3MjEzZDgpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfM2U0ODJmMTEyOTM5NDg2YmEwNTkwNWQ4ZWVhNzE4NmEgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0My45MDIwMSwzOS4zNDYyMzZdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fYjRkMjkxMDY1ODkzNGYzMmI0ZjQ1Y2U4ZmZlNzg3YmEgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JlaWdlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzNlNDgyZjExMjkzOTQ4NmJhMDU5MDVkOGVlYTcxODZhLnNldEljb24oaWNvbl9iNGQyOTEwNjU4OTM0ZjMyYjRmNDVjZThmZmU3ODdiYSk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8wZGRkYzcwOTQzODc0ZDUxOWVhODgwMzllNjQwYzczZCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF83YzEwZjQ1NzMwMWU0YmZkYmIzOTdiZjUwMTE1M2FmMSA9ICQoJzxkaXYgaWQ9Imh0bWxfN2MxMGY0NTczMDFlNGJmZGJiMzk3YmY1MDExNTNhZjEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCU0J7QmyAi0JTQvtC8INC+0YLQtNGL0YXQsCDQmtC+0LvQvtGBIjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMGRkZGM3MDk0Mzg3NGQ1MTllYTg4MDM5ZTY0MGM3M2Quc2V0Q29udGVudChodG1sXzdjMTBmNDU3MzAxZTRiZmRiYjM5N2JmNTAxMTUzYWYxKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfM2U0ODJmMTEyOTM5NDg2YmEwNTkwNWQ4ZWVhNzE4NmEuYmluZFBvcHVwKHBvcHVwXzBkZGRjNzA5NDM4NzRkNTE5ZWE4ODAzOWU2NDBjNzNkKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzVmOGIzMTA5ZjkzNDRiNzg4ZDQwMGVmNDdjZTAxNzAyID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuNTU1MzU0LDM4LjA2NDE1Ml0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl9hN2Q2NjRkODBlMGM0NTZmYTVkMjhjMTI0MzgyY2Y3ZSA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmVpZ2UnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfNWY4YjMxMDlmOTM0NGI3ODhkNDAwZWY0N2NlMDE3MDIuc2V0SWNvbihpY29uX2E3ZDY2NGQ4MGUwYzQ1NmZhNWQyOGMxMjQzODJjZjdlKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzQxMmU4ZDkyZmUwMDQxZDA4MDk4OTNkODY4NjJhYTRlID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2Y5OWE2NjU3NmMzZDRiOGZhYmRjZTAxNGQzMDlhM2FhID0gJCgnPGRpdiBpZD0iaHRtbF9mOTlhNjY1NzZjM2Q0YjhmYWJkY2UwMTRkMzA5YTNhYSIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0JPQvtGA0L7QtNGB0LrQvtC5INC/0LvRj9C2INCc0KPQnyAi0JHQpdCeIjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNDEyZThkOTJmZTAwNDFkMDgwOTg5M2Q4Njg2MmFhNGUuc2V0Q29udGVudChodG1sX2Y5OWE2NjU3NmMzZDRiOGZhYmRjZTAxNGQzMDlhM2FhKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfNWY4YjMxMDlmOTM0NGI3ODhkNDAwZWY0N2NlMDE3MDIuYmluZFBvcHVwKHBvcHVwXzQxMmU4ZDkyZmUwMDQxZDA4MDk4OTNkODY4NjJhYTRlKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzI4NTQ2YTM1ZWJhNjQ5ZWViMjRhZmNkODhiYjgxN2RhID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDUuMzQ4MDA0LDM3LjEyOTg3N10sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl84MGU2YmU0M2M5NWU0MWE5YTAwMjc0YTUwM2M4MGE3YSA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl8yODU0NmEzNWViYTY0OWVlYjI0YWZjZDg4YmI4MTdkYS5zZXRJY29uKGljb25fODBlNmJlNDNjOTVlNDFhOWEwMDI3NGE1MDNjODBhN2EpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNjJmNjg0YjBjMzY4NDBmYjljODdlNTQ0MWNiNzcyMWUgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfZDE2YTJiMzhmMDVhNGEzMWFkYWE0ZTE5MzI4MDdlZDggPSAkKCc8ZGl2IGlkPSJodG1sX2QxNmEyYjM4ZjA1YTRhMzFhZGFhNGUxOTMyODA3ZWQ4IiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDQntC30LTQvtGA0L7QstC40YLQtdC70YzQvdC+0LPQviDRhtC10L3RgtGA0LAgwqvQkdGA0LjQt8K7PC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF82MmY2ODRiMGMzNjg0MGZiOWM4N2U1NDQxY2I3NzIxZS5zZXRDb250ZW50KGh0bWxfZDE2YTJiMzhmMDVhNGEzMWFkYWE0ZTE5MzI4MDdlZDgpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl8yODU0NmEzNWViYTY0OWVlYjI0YWZjZDg4YmI4MTdkYS5iaW5kUG9wdXAocG9wdXBfNjJmNjg0YjBjMzY4NDBmYjljODdlNTQ0MWNiNzcyMWUpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfNDJmMWViOWM1NzkzNGEwOTk0NzlhYjFlZWU5MzgxN2EgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0NC45NDAxODYsMzcuMzEyNDc4XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uXzYxODkxYTlhMzNmMDRmYjM5OWQzMmM3Njc0MGEyZWRmID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdibHVlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzQyZjFlYjljNTc5MzRhMDk5NDc5YWIxZWVlOTM4MTdhLnNldEljb24oaWNvbl82MTg5MWE5YTMzZjA0ZmIzOTlkMzJjNzY3NDBhMmVkZik7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9iMzYwMDg2MDEyYjA0M2NjYTM4OGNmNTAwMTJiNjJhMSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF8yNzAyYWE3ZTgzZWY0NzE3ODBlMWE4MzdlY2U5MzQ0ZSA9ICQoJzxkaXYgaWQ9Imh0bWxfMjcwMmFhN2U4M2VmNDcxNzgwZTFhODM3ZWNlOTM0NGUiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2INC+0LfQtNC+0YDQvtCy0LjRgtC10LvRjNC90L7Qs9C+INC+0LHRitC10LTQuNC90LXQvdC40Y8gwqvQl9C+0LvQvtGC0YvQtSDQv9C10YHQutC4wrsgPC9kaXY+JylbMF07CiAgICAgICAgICAgICAgICBwb3B1cF9iMzYwMDg2MDEyYjA0M2NjYTM4OGNmNTAwMTJiNjJhMS5zZXRDb250ZW50KGh0bWxfMjcwMmFhN2U4M2VmNDcxNzgwZTFhODM3ZWNlOTM0NGUpOwogICAgICAgICAgICAKCiAgICAgICAgICAgIG1hcmtlcl80MmYxZWI5YzU3OTM0YTA5OTQ3OWFiMWVlZTkzODE3YS5iaW5kUG9wdXAocG9wdXBfYjM2MDA4NjAxMmIwNDNjY2EzODhjZjUwMDEyYjYyYTEpOwoKICAgICAgICAgICAgCiAgICAgICAgCiAgICAKCiAgICAgICAgICAgIHZhciBtYXJrZXJfMDY0ZWFkMjgyYTUxNGVlOGEwNTkwMWRiNDJlNmM2MWYgPSBMLm1hcmtlcigKICAgICAgICAgICAgICAgIFs0My45MTg2MSwzOS4zMTkwOF0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl9lNWJlMTg5N2U2YTI0YTczODQ0YmNiYWRhNDZkYTFkZSA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmVpZ2UnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfMDY0ZWFkMjgyYTUxNGVlOGEwNTkwMWRiNDJlNmM2MWYuc2V0SWNvbihpY29uX2U1YmUxODk3ZTZhMjRhNzM4NDRiY2JhZGE0NmRhMWRlKTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzlhNGM2ODgxZDhlZTQyMDNhMmY4NTg0MzE2ZjNhNzkyID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzg0OTQzMjZjYmVkNjRhNWJiMGE2OGJmMjUwMTFmYjQwID0gJCgnPGRpdiBpZD0iaHRtbF84NDk0MzI2Y2JlZDY0YTViYjBhNjhiZjI1MDExZmI0MCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0JfQkNCeICLQodCw0L3QsNGC0L7RgNC40LkgItCc0L7RgNGB0LrQsNGPINC30LLQtdC30LTQsCI8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzlhNGM2ODgxZDhlZTQyMDNhMmY4NTg0MzE2ZjNhNzkyLnNldENvbnRlbnQoaHRtbF84NDk0MzI2Y2JlZDY0YTViYjBhNjhiZjI1MDExZmI0MCk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzA2NGVhZDI4MmE1MTRlZThhMDU5MDFkYjQyZTZjNjFmLmJpbmRQb3B1cChwb3B1cF85YTRjNjg4MWQ4ZWU0MjAzYTJmODU4NDMxNmYzYTc5Mik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl9mNTkzMTEzZTVlOWM0N2M4YTNiYzFhMDQxMDlhNDdhYiA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ0Ljc5MTI5NywzNy40MDIyNTVdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fODY4NTg3ODQ4MTY2NDNmMGEyMWIwY2FkNGE4ZWUwNjggPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JsdWUnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfZjU5MzExM2U1ZTljNDdjOGEzYmMxYTA0MTA5YTQ3YWIuc2V0SWNvbihpY29uXzg2ODU4Nzg0ODE2NjQzZjBhMjFiMGNhZDRhOGVlMDY4KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzIwYmVlZjA4MjFhNTRkNTk5MGI4NzZjNWU5Mjc1ZjlkID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzM1OWM3ZGMzYTEyNzRmNzNiYTg4NzAyZWQ4NDYzODE2ID0gJCgnPGRpdiBpZD0iaHRtbF8zNTljN2RjM2ExMjc0ZjczYmE4ODcwMmVkODQ2MzgxNiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0KTQk9CR0J7QoyDQlNCe0JQg0KTQlNCmICLQodC80LXQvdCwIjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfMjBiZWVmMDgyMWE1NGQ1OTkwYjg3NmM1ZTkyNzVmOWQuc2V0Q29udGVudChodG1sXzM1OWM3ZGMzYTEyNzRmNzNiYTg4NzAyZWQ4NDYzODE2KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfZjU5MzExM2U1ZTljNDdjOGEzYmMxYTA0MTA5YTQ3YWIuYmluZFBvcHVwKHBvcHVwXzIwYmVlZjA4MjFhNTRkNTk5MGI4NzZjNWU5Mjc1ZjlkKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyX2VjZGM5ZDIzMDAyZDQ4NzY5M2E3ODRjOGI2NGM2NWM3ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuNTYyODg4LDM4LjA3NjY4M10sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl9hMjc0ZDM0NzE0ZTc0YjA1OWZjZjEwMzYwNDNiMmUzNiA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnYmx1ZScsCiAgICAgICAgICAgICAgICAgICAgcHJlZml4OiAnZ2x5cGhpY29uJywKICAgICAgICAgICAgICAgICAgICBleHRyYUNsYXNzZXM6ICdmYS1yb3RhdGUtMCcKICAgICAgICAgICAgICAgICAgICB9KTsKICAgICAgICAgICAgICAgIG1hcmtlcl9lY2RjOWQyMzAwMmQ0ODc2OTNhNzg0YzhiNjRjNjVjNy5zZXRJY29uKGljb25fYTI3NGQzNDcxNGU3NGIwNTlmY2YxMDM2MDQzYjJlMzYpOwogICAgICAgICAgICAKICAgIAogICAgICAgICAgICB2YXIgcG9wdXBfNmVlZWFjY2NjOWU2NDkzYWE0MDA0Y2YyOGY3MWQ2MDIgPSBMLnBvcHVwKHttYXhXaWR0aDogJzMwMCd9KTsKCiAgICAgICAgICAgIAogICAgICAgICAgICAgICAgdmFyIGh0bWxfY2I5MTQwNTc1M2NhNDlhZjg0MmYyNmU4YjQ5ZjNiZDIgPSAkKCc8ZGl2IGlkPSJodG1sX2NiOTE0MDU3NTNjYTQ5YWY4NDJmMjZlOGI0OWYzYmQyIiBzdHlsZT0id2lkdGg6IDEwMC4wJTsgaGVpZ2h0OiAxMDAuMCU7Ij7Qn9C70Y/QtiDQntCQ0J4g0KHQsNC90LDRgtC+0YDQuNGPICLQmtGA0LDRgdC90LDRjyDQotCw0LvQutCwIjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNmVlZWFjY2NjOWU2NDkzYWE0MDA0Y2YyOGY3MWQ2MDIuc2V0Q29udGVudChodG1sX2NiOTE0MDU3NTNjYTQ5YWY4NDJmMjZlOGI0OWYzYmQyKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfZWNkYzlkMjMwMDJkNDg3NjkzYTc4NGM4YjY0YzY1YzcuYmluZFBvcHVwKHBvcHVwXzZlZWVhY2NjYzllNjQ5M2FhNDAwNGNmMjhmNzFkNjAyKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzgzMmJkOWJlYTQ4NjQ2NmNhMTAwZjU2NjAzMGMwZDU0ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuMTcxMTMsMzkuMDAyMDY1XSwKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBpY29uOiBuZXcgTC5JY29uLkRlZmF1bHQoKQogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgIC5hZGRUbyhtYXBfNWY2NmJiYzQ2MjA4NGQ0MGFmMTk0NzlkNTk3MzQzY2IpOwogICAgICAgICAgICAKICAgIAoKICAgICAgICAgICAgICAgIHZhciBpY29uX2M4Yzc1ZjMzYzQ1NzQyMjg5M2IxZjk3NThmZWFhMjBkID0gTC5Bd2Vzb21lTWFya2Vycy5pY29uKHsKICAgICAgICAgICAgICAgICAgICBpY29uOiAnJywKICAgICAgICAgICAgICAgICAgICBpY29uQ29sb3I6ICd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3I6ICdibHVlJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzgzMmJkOWJlYTQ4NjQ2NmNhMTAwZjU2NjAzMGMwZDU0LnNldEljb24oaWNvbl9jOGM3NWYzM2M0NTc0MjI4OTNiMWY5NzU4ZmVhYTIwZCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF8wMWQ2ZDJiMzlhY2Y0ZWJhYjNhM2UyNWMyMjRlYWY1YSA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF84ODc0YjI4YWVjZGI0YzU3OTJkNTg0YmMyNDVkNDBmMSA9ICQoJzxkaXYgaWQ9Imh0bWxfODg3NGIyOGFlY2RiNGM1NzkyZDU4NGJjMjQ1ZDQwZjEiIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2INCe0JogwqvQn9GA0L7QvNC10YLQtdC5wrs8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzAxZDZkMmIzOWFjZjRlYmFiM2EzZTI1YzIyNGVhZjVhLnNldENvbnRlbnQoaHRtbF84ODc0YjI4YWVjZGI0YzU3OTJkNTg0YmMyNDVkNDBmMSk7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzgzMmJkOWJlYTQ4NjQ2NmNhMTAwZjU2NjAzMGMwZDU0LmJpbmRQb3B1cChwb3B1cF8wMWQ2ZDJiMzlhY2Y0ZWJhYjNhM2UyNWMyMjRlYWY1YSk7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl83NDA5MDNjNjNhMGQ0ZDYzOGY1YmYzNDU3MDgyMzAwZSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQzLjUzOTcxMywzOS44MDU2MjZdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fY2MzYzdlMDRkYzM4NDRiNjg2YTM4ZGVkM2Y2OTI1MDkgPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2JsdWUnLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfNzQwOTAzYzYzYTBkNGQ2MzhmNWJmMzQ1NzA4MjMwMGUuc2V0SWNvbihpY29uX2NjM2M3ZTA0ZGMzODQ0YjY4NmEzOGRlZDNmNjkyNTA5KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzFlZDAzYzhiNjJlYzQwMjZiYmNlOTA0OTk2ZmU5ZGU2ID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2MwOGRlNzQ5MDBhNDRiMjM4M2UxN2UzMjlhYTRmMTZiID0gJCgnPGRpdiBpZD0iaHRtbF9jMDhkZTc0OTAwYTQ0YjIzODNlMTdlMzI5YWE0ZjE2YiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0J/Qu9GP0LbQvdGL0Lkg0LrQvtC80L/Qu9C10LrRgSDCq9Ch0L/Rg9GC0L3QuNC6wrsg0JDQniDCq9Ch0J7QmiDCq9Ch0L/Rg9GC0L3QuNC6wrs8L2Rpdj4nKVswXTsKICAgICAgICAgICAgICAgIHBvcHVwXzFlZDAzYzhiNjJlYzQwMjZiYmNlOTA0OTk2ZmU5ZGU2LnNldENvbnRlbnQoaHRtbF9jMDhkZTc0OTAwYTQ0YjIzODNlMTdlMzI5YWE0ZjE2Yik7CiAgICAgICAgICAgIAoKICAgICAgICAgICAgbWFya2VyXzc0MDkwM2M2M2EwZDRkNjM4ZjViZjM0NTcwODIzMDBlLmJpbmRQb3B1cChwb3B1cF8xZWQwM2M4YjYyZWM0MDI2YmJjZTkwNDk5NmZlOWRlNik7CgogICAgICAgICAgICAKICAgICAgICAKICAgIAoKICAgICAgICAgICAgdmFyIG1hcmtlcl8wODA4Mjg4MGY4OGM0YWFhODBiYzc5YzA1OTUzMDYwYSA9IEwubWFya2VyKAogICAgICAgICAgICAgICAgWzQ0LjU4Njg2MywzOC4wNDM0NzNdLAogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGljb246IG5ldyBMLkljb24uRGVmYXVsdCgpCiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgLmFkZFRvKG1hcF81ZjY2YmJjNDYyMDg0ZDQwYWYxOTQ3OWQ1OTczNDNjYik7CiAgICAgICAgICAgIAogICAgCgogICAgICAgICAgICAgICAgdmFyIGljb25fNzc5MDE4ZjRlNGFiNDY0Yzk1N2U5NmQ5ZDAxZTdlMDggPSBMLkF3ZXNvbWVNYXJrZXJzLmljb24oewogICAgICAgICAgICAgICAgICAgIGljb246ICcnLAogICAgICAgICAgICAgICAgICAgIGljb25Db2xvcjogJ3doaXRlJywKICAgICAgICAgICAgICAgICAgICBtYXJrZXJDb2xvcjogJ2dyZWVuJywKICAgICAgICAgICAgICAgICAgICBwcmVmaXg6ICdnbHlwaGljb24nLAogICAgICAgICAgICAgICAgICAgIGV4dHJhQ2xhc3NlczogJ2ZhLXJvdGF0ZS0wJwogICAgICAgICAgICAgICAgICAgIH0pOwogICAgICAgICAgICAgICAgbWFya2VyXzA4MDgyODgwZjg4YzRhYWE4MGJjNzljMDU5NTMwNjBhLnNldEljb24oaWNvbl83NzkwMThmNGU0YWI0NjRjOTU3ZTk2ZDlkMDFlN2UwOCk7CiAgICAgICAgICAgIAogICAgCiAgICAgICAgICAgIHZhciBwb3B1cF9hYzBkYzc1ZTE3YWI0MDk0YjYzYzc2YjQyMjY4YmU5NCA9IEwucG9wdXAoe21heFdpZHRoOiAnMzAwJ30pOwoKICAgICAgICAgICAgCiAgICAgICAgICAgICAgICB2YXIgaHRtbF9hNzk3OTkxMGRiYzQ0MmU2YjE5MDhlNzZjNmFkMzQ0NyA9ICQoJzxkaXYgaWQ9Imh0bWxfYTc5Nzk5MTBkYmM0NDJlNmIxOTA4ZTc2YzZhZDM0NDciIHN0eWxlPSJ3aWR0aDogMTAwLjAlOyBoZWlnaHQ6IDEwMC4wJTsiPtCf0LvRj9C2INCX0JDQniDQm9Ce0JogItCh0L7Qu9C90LXRh9C90LDRjyIg0JfQkNCeINCb0J7QmiAi0KHQvtC70L3QtdGH0L3QsNGPIjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfYWMwZGM3NWUxN2FiNDA5NGI2M2M3NmI0MjI2OGJlOTQuc2V0Q29udGVudChodG1sX2E3OTc5OTEwZGJjNDQyZTZiMTkwOGU3NmM2YWQzNDQ3KTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfMDgwODI4ODBmODhjNGFhYTgwYmM3OWMwNTk1MzA2MGEuYmluZFBvcHVwKHBvcHVwX2FjMGRjNzVlMTdhYjQwOTRiNjNjNzZiNDIyNjhiZTk0KTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzZiNGRkNzRhMzhlMjQ1YjVhODlkMzg2OTA3NjFhYjRiID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuNTU1MzU0LDM4LjA2NDE1Ml0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl9iNzc0MDRkMzVlNWE0ZGQ0YThlOTljYjlmNjVhMzhiOSA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnZ3JlZW4nLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfNmI0ZGQ3NGEzOGUyNDViNWE4OWQzODY5MDc2MWFiNGIuc2V0SWNvbihpY29uX2I3NzQwNGQzNWU1YTRkZDRhOGU5OWNiOWY2NWEzOGI5KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzkyYjQ0NTAyOWE2ZDQwZTk5NzdjNmZjN2Q3OTZjMTczID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sXzhmMzk5YTQ0ODM0YjQ0NDhiYWFlMDU3YjdiZjcyODkwID0gJCgnPGRpdiBpZD0iaHRtbF84ZjM5OWE0NDgzNGI0NDQ4YmFhZTA1N2I3YmY3Mjg5MCIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0JPQvtGA0L7QtNGB0LrQvtC5INC/0LvRj9C2INCc0KPQnyAi0JHQpdCeIjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfOTJiNDQ1MDI5YTZkNDBlOTk3N2M2ZmM3ZDc5NmMxNzMuc2V0Q29udGVudChodG1sXzhmMzk5YTQ0ODM0YjQ0NDhiYWFlMDU3YjdiZjcyODkwKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfNmI0ZGQ3NGEzOGUyNDViNWE4OWQzODY5MDc2MWFiNGIuYmluZFBvcHVwKHBvcHVwXzkyYjQ0NTAyOWE2ZDQwZTk5NzdjNmZjN2Q3OTZjMTczKTsKCiAgICAgICAgICAgIAogICAgICAgIAogICAgCgogICAgICAgICAgICB2YXIgbWFya2VyXzgzMWVjNzNmZjc3MDRmZDBiOGY5MzU0M2VhYWJmNjg0ID0gTC5tYXJrZXIoCiAgICAgICAgICAgICAgICBbNDQuNTU1MzU0LDM4LjA2NDE1Ml0sCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCkKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAuYWRkVG8obWFwXzVmNjZiYmM0NjIwODRkNDBhZjE5NDc5ZDU5NzM0M2NiKTsKICAgICAgICAgICAgCiAgICAKCiAgICAgICAgICAgICAgICB2YXIgaWNvbl85ZTQxNmQzMTMxNGQ0ZDgzYmQ4YTJlZDE0MjRiNDYxOSA9IEwuQXdlc29tZU1hcmtlcnMuaWNvbih7CiAgICAgICAgICAgICAgICAgICAgaWNvbjogJycsCiAgICAgICAgICAgICAgICAgICAgaWNvbkNvbG9yOiAnd2hpdGUnLAogICAgICAgICAgICAgICAgICAgIG1hcmtlckNvbG9yOiAnZ3JlZW4nLAogICAgICAgICAgICAgICAgICAgIHByZWZpeDogJ2dseXBoaWNvbicsCiAgICAgICAgICAgICAgICAgICAgZXh0cmFDbGFzc2VzOiAnZmEtcm90YXRlLTAnCiAgICAgICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgICAgICBtYXJrZXJfODMxZWM3M2ZmNzcwNGZkMGI4ZjkzNTQzZWFhYmY2ODQuc2V0SWNvbihpY29uXzllNDE2ZDMxMzE0ZDRkODNiZDhhMmVkMTQyNGI0NjE5KTsKICAgICAgICAgICAgCiAgICAKICAgICAgICAgICAgdmFyIHBvcHVwXzUxYWE0NDMyZGVhMjQyOTRiNGZmM2FjN2ViOTFiNjNkID0gTC5wb3B1cCh7bWF4V2lkdGg6ICczMDAnfSk7CgogICAgICAgICAgICAKICAgICAgICAgICAgICAgIHZhciBodG1sX2IyNjU5OTVhZjAzYTRiYTVhNWFmMWQ2NGJkMjEwNGEyID0gJCgnPGRpdiBpZD0iaHRtbF9iMjY1OTk1YWYwM2E0YmE1YTVhZjFkNjRiZDIxMDRhMiIgc3R5bGU9IndpZHRoOiAxMDAuMCU7IGhlaWdodDogMTAwLjAlOyI+0JPQvtGA0L7QtNGB0LrQvtC5INC/0LvRj9C2INCc0KPQnyAi0JHQpdCeIjwvZGl2PicpWzBdOwogICAgICAgICAgICAgICAgcG9wdXBfNTFhYTQ0MzJkZWEyNDI5NGI0ZmYzYWM3ZWI5MWI2M2Quc2V0Q29udGVudChodG1sX2IyNjU5OTVhZjAzYTRiYTVhNWFmMWQ2NGJkMjEwNGEyKTsKICAgICAgICAgICAgCgogICAgICAgICAgICBtYXJrZXJfODMxZWM3M2ZmNzcwNGZkMGI4ZjkzNTQzZWFhYmY2ODQuYmluZFBvcHVwKHBvcHVwXzUxYWE0NDMyZGVhMjQyOTRiNGZmM2FjN2ViOTFiNjNkKTsKCiAgICAgICAgICAgIAogICAgICAgIAo8L3NjcmlwdD4=\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe></div></div>"
      ],
      "text/plain": [
       "<folium.folium.Map at 0x7fd7049c6160>"
      ]
     },
     "execution_count": 81,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Заключение"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Мы рассмотрели пример, как с помощью scrapy можно спарсить данные с сайта. Надеюсь, тьюториал оказался полезным.\n",
    "Всем хорошего лета!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"kurische_nehrung.jpg\">\n",
    "Не пляж, но тоже прекрасное место - Куршская коса в Калининградской области"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
